Build Events Database

Fish

fish_events<-read_excel(path="/Users/eric/google_drive/MarineGEO/Fish/FISH_DATA_21Jul2017.xlsx",sheet="Events")
### Format events to schema
#change all empty columns from logical to character class
fish_events[sapply(fish_events, is.logical)] <- lapply(fish_events[sapply(fish_events, is.logical)],  as.character)
#change eventID to just the KANF value
fish_events$eventID<-str_extract(fish_events$eventID,"KANF\\d\\d\\d")
#round the lat/longs to four digits (~ 10m uncertainty)
fish_events$decimalLatitude<-round(as.numeric(fish_events$decimalLatitude),digits = 4)
fish_events$decimalLongitude<-round(as.numeric(fish_events$decimalLongitude),digits = 4)
fish_events$coordinateUncertaintyInMeters<-as.numeric(fish_events$coordinateUncertaintyInMeters) 
# class(fish_events$geoReferenceProtocol)
# class(fish_events$maximumDepthInMeters)
# class(fish_events$minimumDepthInMeters)
# class(fish_events$recordedBy) 
# class(fish_events$samplingProtocol) #some missing. ask Diane to fill this in
# class(fish_events$habitatBiotic)
#remove carriage returns from Geomorphological Zone
fish_events$habitatGeomorphologicalZone<-str_replace_all(fish_events$habitatGeomorphologicalZone,pattern="\r\n",replacement = "")
fish_events$habitatSubstrate<-str_replace_all(fish_events$habitatSubstrate,pattern="\r\n",replacement = "")
fish_events$year<-as.numeric(fish_events$year)
fish_events$month<-match(fish_events$month,month.abb)
fish_events$day<-as.numeric(fish_events$day)
#Recommended fields
# class(fish_events$eventRemarks)
# class(fish_events$locality)
# class(fish_events$eventRemarks)
# class(fish_events$verbatimCoordinates)
# class(fish_events$eventMedia)
#remove ending times from eventTime field
fish_events$eventTime<-str_extract(string=fish_events$eventTime,pattern="^\\d\\d:\\d\\d")

Algae

algae_events<-read_excel("/Users/eric/google_drive/MarineGEO/algae/MarineGEOHI_bioassessment_master_KANA.xlsx", sheet="Station")
### Format events to schema
#change all empty columns from logical to character class
algae_events[sapply(algae_events, is.logical)] <- lapply(algae_events[sapply(algae_events, is.logical)],  as.character)
#round to 4 decimal digits (~10m uncertainty) and meake sure longitude is negative
algae_events$decimalLatitude<-round(as.numeric(algae_events$decimalLatitude),digits = 4)
algae_events$decimalLongitude<-abs(round(as.numeric(algae_events$decimalLongitude),digits = 4))*-1
# class(algae_events$eventID)
# class(algae_events$geoReferenceProtocol) #good
# class(algae_events$coordinateUncertaintyInMeters) #good
# class(algae_events$maximumDepthInMeters) #some missing. ask Melinda to fill this in
# class(algae_events$minimumDepthInMeters)#some missing. ask Melinda to fill this in
# class(algae_events$recordedBy) #some missing. ask Melinda to fill this in
# class(algae_events$samplingProtocol) #some missing. ask Melinda to fill this in
# class(algae_events$`habitatBiotic`)
# class(algae_events$`habitatGeomorphologicalZone`)
# class(algae_events$`habitatSubstrate`)
#Recommended fields
# class(algae_events$eventRemarks)
# class(algae_events$locality)
# class(algae_events$eventRemarks)
# class(algae_events$verbatimCoordinates)
# class(algae_events$eventMedia)
#format time correctly
algae_events$eventTime<-as.character(parse_date_time(algae_events$eventTime, orders="ymdHMS", tz="HST"),format="%H:%M")

Macroinvertebrates

invert_events<-read_excel(path="/Users/eric/google_drive/MarineGEO/Inverts/BKANE_063017_FIMS.xlsx", sheet = "Station", skip=2)
### Format events to schema
# Note: invert event data need a lot of cleaning, including importing stations from the algae and meiofauna team, and making new stations with "A" or "B" appended. Currently 839 samples do not have station information because of this.
# remove event fields that don't appear in the schema
invert_events<-invert_events[,-grep(pattern = "^X",x = names(invert_events),perl=T)]
#change all empty columns from logical to character class
invert_events[sapply(invert_events, is.logical)] <- lapply(invert_events[sapply(invert_events, is.logical)],  as.character)
#round to 4 decimal digits (~10m uncertainty) and meake sure longitude is negative
invert_events$decimalLatitude<-round(as.numeric(invert_events$decimalLatitude),digits = 4)
invert_events$decimalLongitude<-abs(round(as.numeric(invert_events$decimalLongitude),digits = 4))*-1
invert_events$geoReferenceProtocol<-"GPS"
invert_events$coordinateUncertaintyInMeters<-100
# class(invert_events$maximumDepthInMeters) #some missing. ask John to fill this in
# class(invert_events$minimumDepthInMeters)#some missing. ask John to fill this in
#Format the date properly, get rid of the "raw" field
invert_events$day<-day(invert_events$eventDate)
invert_events$month<-month(invert_events$eventDate)
invert_events$year<-year(invert_events$eventDate)
invert_events$eventDate<-NULL
# class(invert_events$recordedBy) #good
# class(invert_events$samplingProtocol) #some missing. ask John to fill this in
# class(invert_events$habitatGeomorphologicalZone) #some missing. ask John to fill this in. #this needs to be aligned with the schema
# class(invert_events$habitatSubstrate) # some missing. ask John to fill this in. #this needs to be aligned with the schema
#Recommended fields
# class(invert_events$locality)
# class(invert_events$eventRemarks)

Meiofauna

meio_events<-read_excel(path="/Users/eric/google_drive/MarineGEO/Meiofauna/Hawaii2017_meiofauna_MarineGEO.xlsx", sheet = "station data", skip=1)
#remove columns that don't appear in MarineGEO schema
meio_events<-meio_events[,-grep(pattern = "^X",x = names(meio_events),perl=T)]
### Format events to schema
#Missing station KANM087!!!
#change all empty columns from logical to character class
meio_events[sapply(meio_events, is.logical)] <- lapply(meio_events[sapply(meio_events, is.logical)],  as.character)
#round to 4 decimal digits (~10m uncertainty) and meake sure longitude is negative
meio_events$decimalLatitude<-round(as.numeric(meio_events$decimalLatitude),digits = 4)
meio_events$decimalLongitude<-abs(round(as.numeric(meio_events$decimalLongitude),digits = 4))*-1
meio_events$coordinateUncertaintyInMeters<-100
meio_events$minimumDepthInMeters<-as.numeric(meio_events$minimumDepthInMeters)
meio_events$maximumDepthInMeters<-as.numeric(meio_events$maximumDepthInMeters)
# class(meio_events$maximumDepthInMeters)
# class(meio_events$minimumDepthInMeters)
# class(meio_events$recordedBy) #ask Freya to follow format - add last names, and pipes between names
# class(meio_events$samplingProtocol) #some missing. ask Freya to fill this in
# class(meio_events$habitatGeomorphologicalZone) #some missing. ask Freya to fill this in
# class(meio_events$habitatSubstrate) # some missing. ask Freya to fill this in
# class(meio_events$habitatBiotic)
#Recommended fields
# class(meio_events$locality)
# class(meio_events$eventRemarks)
meio_events$day<-day(meio_events$eventDate)
meio_events$month<-month(meio_events$eventDate)
meio_events$year<-year(meio_events$eventDate)
meio_events$eventDate<-NULL
#format the $^#&* time correctly
meio_events$eventTime<-format(.POSIXct(86400*as.numeric(meio_events$eventTime), "UTC"), "%H:%M")
#meio_events$eventTime<-as.character(parse_date_time(meio_events$eventTime, orders="ymdHMS", tz="HST"),format="%H:%M")
meio_events$eventMedia<-"N"

ARMS

arms_events<-read_excel(path="/Users/eric/google_drive/MarineGEO/ARMS/MarineGEOHI_bioassessment_master-ARMS.xlsx", sheet = "Station")
### Format events to schema
#change all empty columns from logical to character class
arms_events[sapply(arms_events, is.logical)] <- lapply(arms_events[sapply(arms_events, is.logical)],  as.character)
#round to 4 decimal digits (~10m uncertainty) and meake sure longitude is negative
arms_events$decimalLatitude<-round(as.numeric(arms_events$decimalLatitude),digits = 4)
arms_events$decimalLongitude<-abs(round(as.numeric(arms_events$decimalLongitude),digits = 4))*-1
arms_events$coordinateUncertaintyInMeters<-10
arms_events$minimumDepthInMeters<-as.numeric(arms_events$minimumDepthInMeters)
# class(arms_events$geoReferenceProtocol)
# class(arms_events$eventID)
# class(arms_events$maximumDepthInMeters)
# class(arms_events$recordedBy) #ask Laetitia to follow name format
# class(arms_events$samplingProtocol)
# class(arms_events$habitatGeomorphologicalZone)
# class(arms_events$habitatSubstrate) 
# class(arms_events$habitatBiotic)
#Recommended fields
# class(arms_events$locality)
# class(arms_events$year)
# class(arms_events$month)
# class(arms_events$day)
arms_events$eventMedia<-"Y" #still need to get these from Laetitia

Visual Transects

trans_events<-read_excel(path="/Users/eric/google_drive/MarineGEO/Transects/bioassessment_KANV.xlsx", sheet = "Station")
trans_event_photos<-read_excel(path="/Users/eric/google_drive/MarineGEO/Transects/KANV_benthic-photos_filenames_20170711.xlsx", sheet = "Sheet1")
# event photos
#pop off the eventID into its own field
trans_event_photos$eventID<-sub(pattern="(KANV\\d\\d\\d)_.+",replacement = "\\1", trans_event_photos$eventMedia, perl=T)
#use ddply to lump all eventMedia into a single field, separated by a |
trans_eventMedia<-ddply(trans_event_photos, "eventID", transform, eventMedia = paste(eventMedia, collapse = "|"))
#keep only the first instance of each occurrenceID
trans_eventMedia<-trans_eventMedia[!duplicated(trans_eventMedia$eventID),]
#delete original eventMedia column and join on the new one
trans_events$eventMedia<-NULL
trans_events<-left_join(trans_events, trans_eventMedia, by="eventID")
### Format events to schema
#change all empty columns from logical to character class
trans_events[sapply(trans_events, is.logical)] <- lapply(trans_events[sapply(trans_events, is.logical)],  as.character)
#round to 4 decimal digits (~10m uncertainty) and meake sure longitude is negative
trans_events$decimalLatitude<-round(as.numeric(trans_events$decimalLatitude),digits = 4)
trans_events$decimalLongitude<-abs(round(as.numeric(trans_events$decimalLongitude),digits = 4))*-1
trans_events$minimumDepthInMeters<-as.numeric(trans_events$minimumDepthInMeters)
# class(trans_events$eventID)
# class(trans_events$coordinateUncertaintyInMeters)
# class(trans_events$maximumDepthInMeters)
# class(trans_events$recordedBy) 
# class(trans_events$samplingProtocol)
# class(trans_events$habitatGeomorphologicalZone)
# class(trans_events$habitatSubstrate)
# class(trans_events$habitatBiotic)
#Recommended fields
# class(trans_events$locality)
# class(trans_events$year)
# class(trans_events$month)
# class(trans_events$day)
trans_events$eventTime<-as.character(parse_date_time(trans_events$eventTime, orders="ymdHMS", tz="HST"),format="%H:%M")

Join Events

events<-full_join(fish_events,algae_events)
events<-full_join(events,invert_events)
events<-full_join(events,meio_events)
events<-full_join(events,arms_events)
events<-full_join(events,trans_events)

Build sample databases

Fish

Import

# First go through and make sure all stations have Lat/Longs, or as many as possible. Delete secondary lat/longs
#read in the sample data, skipping first 3 lines of other headers. Format all times as hh:mm in Excel, paste into textwrangler if they need homogenization (i.e. multiple formats of times)
fish_samples<-read_excel(path="/Users/eric/google_drive/MarineGEO/Fish/FISH_DATA_21Jul2017.xlsx",sheet="Samples")
fish_genetic<-read_excel(path="/Users/eric/google_drive/MarineGEO/Fish/FISH_DATA_21Jul2017.xlsx",sheet="Genetic samples")
#these commands apply to the original fish-group template
#remove columns without mapped DwC terms mapped
#fish_samples<-fish_samples[,-grep(pattern = "^X",x = names(fish_samples),perl=T)]
#fish_events<-fish_events[,-grep(pattern = "^X",x = names(fish_events),perl=T)]
#remove records without occurrenceIDs (temp before final dataset)
#fish_samples<-fish_samples[-which(is.na(fish_samples$occurrenceID)),]
#translate fieldIDs to eventIDs
#fish_samples$eventID<-gsub("LRP 17-","KANF0",fish_samples$eventID)
#use ddply to lump all materialSampleIDs into a single field, separated by a |
#fish_samples<-ddply(fish_samples, "occurrenceID", transform, materialSampleID = #paste(materialSampleID, collapse = "|"))
#keep only the first instance of each occurrenceID
#fish_samples<-fish_samples[!duplicated(fish_samples$occurrenceID),]

Format samples to schema

#change all empty columns from logical to character class
fish_samples[sapply(fish_samples, is.logical)] <- lapply(fish_samples[sapply(fish_samples, is.logical)],  as.character)
#Fix the eventIDs
fish_samples$eventID<-str_extract(fish_samples$eventID,"KANF\\d\\d\\d")
fish_samples$otherCatalogNumbers<-NULL # drop this for now - it will be replaced by fish_biorep below
# class(fish_samples[,which(sapply(fish_samples, is.logical))])<-"character"
# class(fish_samples$occurrenceID)
# class(fish_samples$basisofRecord)
# class(fish_samples$catalogNumber)<-"character"
# class(fish_samples$organismScope)
# class(fish_samples$eventID)
# class(fish_samples$scientificName) #eventually parse this into taxon categories?
# class(fish_samples$taxonRank) #using this
# class(fish_samples$individualCount)
# class(fish_samples$institutionID)
# make identifiedBy go firstname lastname
fish_samples$identifiedBy<-str_replace(fish_samples$identifiedBy, pattern="(\\w+), (.+)", replacement="\\2 \\1")
fish_samples$catalogNumber<-as.character(fish_samples$catalogNumber)

Format the biorepository info

colnames(fish_genetic)[5]<-"BiorepositoryID"
colnames(fish_genetic)[6]<-"tissueNotes"
colnames(fish_genetic)[2]<-"occurrenceID"
#use ddply to lump all materialSampleIDs into a single field, separated by a |
fish_biorep<-ddply(fish_genetic, "occurrenceID", transform, otherCatalogNumbers = paste(BiorepositoryID, collapse = "|"), tissueNotes = paste(tissueNotes, collapse="|"))
#keep only the first instance of each occurrenceID
fish_biorep<-fish_biorep[!duplicated(fish_biorep$otherCatalogNumbers),]
fish_biorep$otherCatalogNumbers<-as.character(fish_biorep$otherCatalogNumbers)

Join the event data onto the occurrence data

#first join the biorep numbers to this data
fish_samples<-left_join(fish_samples,fish_biorep[,c(2,6,7)],by="occurrenceID")
#now join samples and events
fish<-left_join(fish_samples,events,by="eventID")

Make a Map

#optionally make it from the points provided
#bbox<-make_bbox(lon=fish2$decimalLongitude,lat=fish2$decimalLatitude)
#by individual
fish2<-fish %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(count=n()) 
#by species
fish3 <- fish %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n())
#richness
fish4<-fish3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
fish6<-left_join(fish2,fish4)
fish_map<-ggmap(dmap) + geom_point(data = fish6, mapping = aes(x = decimalLongitude, y = decimalLatitude, size=count, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Species Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank())
fish_map
ggsave(fish_map,filename="./output/fish_map.pdf")

Algae

Import

#edit eventIDs for capitalization
algae_samples<-read_excel("/Users/eric/google_drive/MarineGEO/algae/MarineGEOHI_bioassessment_master_KANA.xlsx", sheet="Sample")

Format samples to schema

#change all empty columns from logical to character class
algae_samples[sapply(algae_samples, is.logical)] <- lapply(algae_samples[sapply(algae_samples, is.logical)],  as.character)
# class(algae_samples$occurrenceID)
# class(algae_samples$catalogNumber)
# class(algae_samples$otherCatalogNumbers)
# class(algae_samples$organismScope)
# class(algae_samples$eventID)
# class(algae_samples$scientificName) #eventually parse this into taxon categories?
# class(algae_samples$taxonRank) # Melinda needs to populate this...
# class(algae_samples$identifiedBy)
# class(algae_samples$individualCount)
algae_samples$basisofRecord<-"specimen"
algae_samples$institutionID<-"USNM"

Join the event data onto the occurrence data

algae<-left_join(algae_samples,events,by="eventID")

Make A Map

#by individual
algae2<-algae %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(count=n()) 
#by species
algae3 <- algae[-which(algae$scientificName=="?"),] %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n())
#richness
algae4<-algae3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
algae5<-left_join(algae2,algae4)
#algae5<-algae5[which(is.na(algae5$decimalLatitude)),]
#algae5<-algae5[-which(algae5$scientificName=="?"),]
algae5[4,4]<-1
algae5[11,4]<-2
extra<-algae5[33,]
algae5<-algae5[-33,] #remove outlier
algae_map<-ggmap(dmap) + geom_point(data = algae5, mapping = aes(x = decimalLongitude, y = decimalLatitude, size=count, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Type Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank()) + geom_point(data=extra, mapping=aes(x = decimalLongitude, y = decimalLatitude, size=30, color=30))
#add outlier back in as a red dot size=30
algae_map
ggsave(algae_map,filename="./output/algae_map.pdf")

Macroinvertebrates

Import

invert_samples<-read_excel(path="/Users/eric/google_drive/MarineGEO/Inverts/BKANE_063017_FIMS.xlsx", sheet = "Specimen",skip=3)
#sponges will be loaded here, cleaned up, and then joined with the rest of the inverts
sponge_samples<-read_excel(path="/Users/eric/google_drive/MarineGEO/Sponges/VICENTE_BIOBLITZ2017_SPONGEMETADATA_FIMS.xlsx", sheet = "Sheet1",skip=1)
#remove columns that don't appear in MarineGEO schema
invert_samples<-invert_samples[,-grep(pattern = "^X",x = names(invert_samples),perl=T)]
sponge_samples<-sponge_samples[,-grep(pattern = "^X",x = names(sponge_samples),perl=T)]
#remove records without occurrenceIDs (temp before final dataset)
invert_samples<-invert_samples[-which(is.na(invert_samples$scientificName)),]
sponge_samples<-sponge_samples[-which(is.na(sponge_samples$scientificName)),]
#change all empty columns from logical to character class
invert_samples[sapply(invert_samples, is.logical)] <- lapply(invert_samples[sapply(invert_samples, is.logical)],  as.character)
sponge_samples[sapply(sponge_samples, is.logical)] <- lapply(sponge_samples[sapply(sponge_samples, is.logical)],  as.character)
sponge_samples$phylum[which(is.na(sponge_samples$phylum))]<-"Porifera"
sponge_samples$eventID<-str_replace(sponge_samples$eventID,pattern="-", replacement="")
invert_samples<-full_join(invert_samples,sponge_samples)

Taxonomize

This code will populate taxonRank with the lowest known taxonomic category

invert_samples$taxonRank[which(!is.na(invert_samples$phylum))]<-"phylum"
invert_samples$taxonRank[which(!is.na(invert_samples$class))]<-"class"
invert_samples$taxonRank[which(!is.na(invert_samples$subclass))]<-"subclass"
invert_samples$taxonRank[which(!is.na(invert_samples$order))]<-"order"
invert_samples$taxonRank[which(!is.na(invert_samples$suborder))]<-"suborder"
invert_samples$taxonRank[which(!is.na(invert_samples$superfamily))]<-"superfamily"
invert_samples$taxonRank[which(!is.na(invert_samples$family))]<-"family"
invert_samples$taxonRank[which(!is.na(invert_samples$subfamily))]<-"subfamily"
invert_samples$taxonRank[which(!is.na(invert_samples$genus))]<-"genus"
invert_samples$taxonRank[which(!is.na(invert_samples$species))]<-"species"
invert_samples$taxonRank[grep("sp\\.",invert_samples$species)]<-"genus"

Format samples to schema

str_replace(string=invert_samples$eventID, pattern="(KAN\\w\\d\\d\\d)[A-Z]",replacement="\\1")
   [1] "KANI001"       "KANI001"       "KANI001"       "KANI001"       "KANI001"      
   [6] "KANI001"       "KANI001"       "KANI001"       "KANI001"       "KANI001"      
  [11] "KANI001"       "KANI001"       "KANI005"       "KANI005"       "KANI001"      
  [16] "KANI001"       "KANI001"       "KANI001"       "KANI001"       "KANI001"      
  [21] "KANI001"       "KANI001"       "KANI001"       "KANI001"       "KANI001"      
  [26] "KANI001"       "KANI001"       "KANI006"       "KANI001"       "KANI001"      
  [31] "KANI001"       "KANI005"       "KANI005"       "KANI005"       "KANI001"      
  [36] "KANI006"       "KANI006"       "KANI006"       "KANI005"       "KANI006"      
  [41] "KANI006"       "KANI006"       "KANI006"       "KANI001"       "KANI006"      
  [46] "KANI006"       "KANI006"       "KANI006"       "KANI005"       "KANI006"      
  [51] "KANI005"       "KANI006"       "KANI006"       "KANI003"       "KANI003"      
  [56] "KANF"          "KANI006"       "KANI006"       "KANI006"       "KANI006"      
  [61] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
  [66] "KANI004"       "KANI013"       "KANI013"       "KANI013"       "KANI013"      
  [71] "KANI012"       "KANI012"       "KANI012"       "KANI012"       "KANI012"      
  [76] "KANI012"       "KANI013"       "KANI017"       "KANI017"       "KANI017"      
  [81] "KANI017"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
  [86] "KANI019"       "KANI019"       "KANI019"       "KANI021"       "KANI021"      
  [91] "KANI020"       "KANI024"       "KANI024"       "KANI027"       "KANI028"      
  [96] "KANI001"       "KANI027"       "KANI028"       "KANI029"       "KANI029"      
 [101] "KANI027"       "KANI028"       "KANI027"       "KANI028"       "KANI028"      
 [106] "KANI028"       "KANI033"       "KANI033"       "KANI033"       "KANI033"      
 [111] "KANI033"       "KANI037"       "KANI033"       "KANI033"       "KANI039"      
 [116] "KANI041"       "KANI043"       "KANI041"       "KANI041"       "KANI049"      
 [121] "KANA001"       "KANI004"       "KANI008"       "KANI008"       "KANI008"      
 [126] "KANI008"       "KANI006"       "KANI003"       "KANI006"       "KANI006"      
 [131] "KANI006"       "KANI005"       "KANI005"       "KANI008"       "KANI006"      
 [136] "KANI006"       "KANI006"       "KANI006"       "KANI006"       "KANI006"      
 [141] "KANM003"       "KANI006"       "KANI007"       "KANI007"       "KANI004"      
 [146] "KANI009"       "KANI009"       "KANI007"       "KANI007"       "KANI007"      
 [151] "KANI009"       "KANI009"       "KANI009"       "KANI004"       "KANI004"      
 [156] "KANI009"       "KANI009"       "KANI004"       "KANI004"       "KANI004"      
 [161] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [166] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [171] "KANI001"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [176] "KANI004"       "KANI004"       "KANI004"       "KANI009"       "KANI009"      
 [181] "KANI009"       "KANI004"       "KANI009"       "KANI009"       "KANI009"      
 [186] "KANI009"       "KANI009"       "KANI009"       "KANI009"       "KANI009"      
 [191] "KANI009"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [196] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [201] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [206] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [211] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI010"      
 [216] "KANI010"       "KANI010"       "KANI010"       "KANI010"       "KANI011"      
 [221] "KANI010"       "KANI004"       "KANI004"       "KANI004"       "KANI013"      
 [226] "KANI013"       "KANI012"       "KANI012"       "KANI012"       "KANI012"      
 [231] NA              "KANI012"       "KANI012"       "KANI012"       "KANI012"      
 [236] "KANI012"       "KANI012"       "KANI012"       "KANI004"       "KANI004"      
 [241] "KANI012"       "KANI012"       "KANI013"       "KANI004"       "KANI004"      
 [246] "KANM007"       "KANM023"       "KANI004"       "KANI004"       "KANI004"      
 [251] "KANI004"       "KANI004"       "KANI004"       "KANI004"       "KANI004"      
 [256] "KANI013"       "KANI013"       "KANI015"       "KANI006"       "KANI004"      
 [261] "KANI013"       "KANI013"       "KANI013"       "KANI013"       "KANI013"      
 [266] "KANI013"       "KANI013"       "KANI013"       "KANI013"       NA             
 [271] "KANI002"       "KANI002"       "KANI001"       "KANI002"       "KANI002"      
 [276] "KANI002"       "KANI002"       "KANI002"       "KANI013"       "KANI013"      
 [281] "KANI013"       "KANA006"       "KANA006"       "KANA006"       "KANA006"      
 [286] "KANI001"       "KANI001"       "KANI013"       "KANI013"       "KANI004"      
 [291] "KANI013"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [296] "KANI015"       "KANI015"       "KANI013"       "KANI015"       "KANI013"      
 [301] "KANI001"       "KANI018"       "KANI019"       "KANI024"       "KANI022"      
 [306] "KANI035"       "KANI034"       "KANI037"       "KANI035"       "KANI034"      
 [311] "KANI043"       NA              "KANI046"       "KANI050"       "KANI048"      
 [316] "KANI060"       "KANI060"       "KANI055"       "KANI060"       "KANI060"      
 [321] "KANI055"       "KANI055"       "KANI066"       NA              "KANI076"      
 [326] "KANI076"       NA              NA              "KANI013"       "KANI013"      
 [331] "KANI013"       "KANI013"       "KANI013"       "KANI013"       "KANI013"      
 [336] "KANI013"       "KANI013"       "KANI013"       "KANI013"       "KANI013"      
 [341] "KANI015"       "KANI013"       "KANI013"       "KANI015"       "KANI015"      
 [346] "KANI015"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [351] "KANI015"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [356] "KANI012"       "KANI012"       "KANI014"       "KANI014"       "KANI013"      
 [361] "KANI013"       "KANI013"       "KANI013"       "KANI013"       "KANI013"      
 [366] "KANI014"       "KANI014"       "KANI014"       "KANI013"       "KANI015"      
 [371] "KANI015"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [376] "KANI015"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [381] "KANI015"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [386] "KANI015"       "KANI015"       "KANI015"       "KANI015"       "KANI015"      
 [391] "KANI016"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [396] "KANI016"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [401] "KANI016"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [406] "KANI015"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [411] "KANI016"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [416] "KANI016"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [421] "KANI016"       "KANI016"       "KANI016"       "KANI016"       "KANI016"      
 [426] "KANI016"       NA              "KANI015"       "KANI013"       "KANI016"      
 [431] "KANI016"       "KANI016"       "KANI013"       "KANI001"       "KANI015"      
 [436] "KANI016"       "KANI013"       "KANI013"       "KANI004"       "KANI004"      
 [441] "KANM020"       "KANM020"       "KANM020"       "KANM020"       "KANM008"      
 [446] "KANM008"       "KANM008"       "KANI016"       "KANI018"       "KANI018"      
 [451] "KANI018"       "KANI018"       "KANI018"       "KANI018"       "KANI018"      
 [456] "KANM020"       "KANM020"       "KANI017"       "KANI018"       "KANM020"      
 [461] "KANM020"       "KANI017"       "KANI017"       "KANI017"       "KANI017"      
 [466] "KANI017"       "KANI017"       "KANI017"       "KANI018"       "KANI017"      
 [471] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [476] "KANI019"       "KANI019"       "KANI016"       "KANI017"       "KANI017"      
 [481] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "KANI017"      
 [486] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "5/24 am ?"    
 [491] "KANI019"       "KANI019"       "KANI017"       "KANI017"       "KANI018"      
 [496] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "KANI017"      
 [501] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "KANI017"      
 [506] "KANI017"       "KANI017"       "KANI017"       "KANI019"       "KANI017"      
 [511] "KANI017"       "KANI017"       "KANI017"       "KANI019"       "KANI017"      
 [516] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [521] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [526] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [531] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [536] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [541] "KANI019"       "KANI019"       "KANI018"       "KANI019"       "KANI019"      
 [546] "KANI019"       "KANI019"       "KANI019"       "KANI017"       "KANI017"      
 [551] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "KANI017"      
 [556] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "KANI017"      
 [561] "KANI017"       "KANI017"       "KANI017"       "KANI017"       "KANI019"      
 [566] "KANI017"       "KANI018"       "KANI014"       "KANI019"       "KANI019"      
 [571] "KANI019"       "T19"           "T19"           "KANI019"       "KANI019"      
 [576] "KANI019"       "KANI019"       "KANI019"       "KANI020"       "KANI020"      
 [581] "KANI020"       "KANI020"       "KANI019"       "KANI019"       "KANI019"      
 [586] "KANI022"       "KANI022"       "KANI022"       "KANI022"       "KANI022"      
 [591] "KANI022"       "KANA016"       "KANA016"       "KANA016"       "KANI022"      
 [596] "KANI022"       "KANI022"       "KANI022"       "KANI022"       "KANI022"      
 [601] "KANI022"       "MXW002"        "MXW002"        "MXW002"        "MXW002"       
 [606] "MXW001"        "MXW001 or 002" "MXW001 or 002" "KANI020"       "KANI020"      
 [611] "KANI020"       "KANI020"       "KANI020"       "KANI020"       "KANI020"      
 [616] "KANI020"       "KANI020"       "KANI020"       "KANI020"       "KANI020"      
 [621] "KANI020"       "KANI020"       "KANI020"       "KANI020"       "KANI020"      
 [626] "KANI022"       "KANI020"       "KANI020"       "KANI022"       "KANI019"      
 [631] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI020"      
 [636] "KANI020"       "KANM031"       "KANI023"       "KANI023"       "KANI022"      
 [641] "KANI020"       "KANI020"       "KANI020"       "KANI020"       "KANI023"      
 [646] "KANI023"       "KANI023"       "KANI023"       "KANI023"       "KANA016"      
 [651] "KANA016"       "KANI022"       "KANI022"       "KANI022"       "KANI022"      
 [656] "KANI022"       "KANI022"       "KANI021"       "KANI021"       "KANI021"      
 [661] "KANI021"       "KANI024"       "KANI021"       "KANI022"       "KANI021"      
 [666] "KANI021"       "KANI024"       "KANI019"       "KANI024"       "KANI024"      
 [671] "KANI019"       "KANI022"       "KANM031"       "KANI024"       "KANI019"      
 [676] "KANI019"       "KANI019"       "KANI024"       "KANI024"       "KANI019"      
 [681] "KANI019"       "KANI022"       "KANI022"       "KANI019"       "KANI019"      
 [686] "KANI019"       "KANI024"       "KANI022"       "KANI022"       "KANI022"      
 [691] "KANI022"       "KANI022"       "KANI024"       "KANI024"       "KANI022"      
 [696] "KANI022"       "KANI022"       "KANI022"       "KANI021"       "KANI022"      
 [701] "KANI022"       "KANI024"       "KANI024"       "KANI024"       "KANI022"      
 [706] "KANI022"       "KANI022"       "KANI022"       "KANI022"       "KANI022"      
 [711] "KANI022"       "KANI022"       "KANI022"       "KANI022"       "KANI022"      
 [716] "KANI022"       "KANI022"       "KANI022"       "KANI022"       "KANI024"      
 [721] "KANI024"       "KANI024"       "KANI022"       "KANI022"       "KANI022"      
 [726] "KANI022"       "KANI022"       "KANI022"       "KANI024"       "KANI022"      
 [731] "KANI024"       "KANI024"       "KANI022"       "KANI022"       "KANI024"      
 [736] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [741] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [746] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [751] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [756] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [761] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [766] "KANI024"       "KANI024"       "KANI024"       "KANI022"       "KANI024"      
 [771] "KANI023"       "KANI023"       "KANI014"       "KANI014"       "KANI014"      
 [776] "KANI014"       "KANI014"       "KANI022"       "KANI019"       "KANI019"      
 [781] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [786] "KANI019"       "KANI019"       "KANI019"       "KANI019"       "KANI019"      
 [791] "KANI019"       "KANI024"       "KANI024"       "KANI024"       "KANI024"      
 [796] "KANI019"       "KANI019"       "KANI025"       "KANM037"       "KANI027"      
 [801] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [806] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [811] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [816] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [821] "KANI001"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [826] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [831] "KANA025"       "KANA025"       "KANA025"       "KANI029"       "KANI029"      
 [836] "KANI029"       "KANI029"       "KANI029"       "KANI029"       "KANI029"      
 [841] "KANI028"       "KANI028"       "KANI028"       "KANI028"       "KANI028"      
 [846] "KANI028"       "KANI028"       "KANI029"       "KANI029"       "KANBZ001"     
 [851] "KANBZ002"      "KANBZ003"      "KANBZ004"      "KANBZ005"      "KANBZ006"     
 [856] "KANBZ007"      "KANBZ008"      "KANBZ008"      "KANBZ010"      "KANBZ013"     
 [861] "KANBZ014"      "KANI001"       "KANI031"       "MXW003"        "MXW003"       
 [866] "KANI025"       "KANI025"       "KANI001"       "KANI024"       "KANI028"      
 [871] "KANI032"       "KANI032"       "KANI032"       "KANI032"       "KANI032"      
 [876] "KANI032"       "KANI032"       "KANI032"       "KANI032"       "KANI032"      
 [881] "KANF019"       "KANF019"       "KANF019"       "KANF019"       "KANI032"      
 [886] "KANI001"       "KANI030"       "KANI030"       "KANI030"       "KANI028"      
 [891] "KANI029"       "KANI029"       "KANI029"       "KANI029"       "KANI029"      
 [896] "KANI030"       "KANI027"       "KANI027"       "KANI030"       "KANI027"      
 [901] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [906] "KANI027"       "KANI027"       "KANI027"       "KANI027"       "KANI027"      
 [911] "KANI027"       "KANI027"       "KANI027"       "KANI030"       "KANI028"      
 [916] "KANI030"       "KANI030"       "KANI027"       "KANI024"       "KANI024"      
 [921] "KANI024"       "KANI024"       "KANI024"       "KANI024"       "KANI022"      
 [926] "KANI022"       "KANI022"       "KANI022"       "KANI022"       "KANI022"      
 [931] "KANI030"       "KANI030"       "KANI024"       "KANI024"       "KANI024"      
 [936] "KANI022"       "KANI022"       "KANI030"       "KANI030"       "KANI030"      
 [941] "KANI030"       "KANI030"       "KANI030"       "KANI030"       "KANI030"      
 [946] "KANI030"       "KANI030"       "KANI030"       "KANI030"       "KANI025"      
 [951] "KANI025"       "KANI025"       "KANI025"       "KANI001"       "KANI035"      
 [956] "KANI035"       "KANI035"       "KANI035"       "KANI035"       "KANI035"      
 [961] "KANI035"       "KANI034"       "KANI034"       "KANI034"       "KANI034"      
 [966] "KANI034"       "KANI034"       "KANI034"       "KANI030"       "KANI030"      
 [971] "KANI030"       "KANI033"       "KANI033"       "KANI000"       "KANI037"      
 [976] "KANI037"       "KANI037"       "KANI037"       "KANI021"       "KANI021"      
 [981] "KANI021"       "KANI021"       "KANI019"       "KANI021"       "KANI021"      
 [986] "KANI021"       "KANI021"       "KANI021"       "KANI021"       "KANI021"      
 [991] "KANI023"       "KANI023"       "KANI023"       "KANI023"       "KANI023"      
 [996] "KANI023"       "KANI023"       "KANI022"       "KANI023"       "KANI029"      
 [ reached getOption("max.print") -- omitted 1488 entries ]

Join the event data onto the occurrence data

invert<-left_join(invert_samples,events,by="eventID")

Make A Map

#by individual
invert2<-invert %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(individualCount=sum(individualCount,na.rm = T)) 
#by species
invert3 <- invert %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n())
#richness
invert4<-invert3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
invert5<-left_join(invert2,invert4)
invert_map<-ggmap(dmap) + geom_point(data = invert5[-c(length(invert5$richness)-1,length(invert5$richness)),], mapping = aes(x = decimalLongitude, y = decimalLatitude, size=individualCount, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Type Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank()) 
invert_map
ggsave(invert_map,filename="./output/invert_map.pdf")

#create a vector of the eventIDs not finding a match in the events database
bad_eventIDs<-invert$eventID[which(is.na(invert$decimalLatitude))]

Make A Sponge Map

sponge<-invert[which(invert$phylum=="Porifera"),]
#by individual
sponge2<-sponge %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(individualCount=sum(individualCount,na.rm = T)) 
#by species
sponge3 <- sponge %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n())
#richness
sponge4<-sponge3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
sponge5<-left_join(sponge2,sponge4)
sponge_map<-ggmap(dmap) + geom_point(data = sponge5[-c(61,62),], mapping = aes(x = decimalLongitude, y = decimalLatitude, size=individualCount, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Type Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank()) 
sponge_map
ggsave(sponge_map,filename="./output/sponge_map.pdf")

Meiofauna

Import

#note meio data still need some cleaning, including importing some stations from inverts and fish, and fixing up eventIDs to have 3 digits instead of 2. There are 27 specimens that do not have station information because of this.
meio_samples<-read_excel(path="/Users/eric/google_drive/MarineGEO/Meiofauna/Hawaii2017_meiofauna_MarineGEO.xlsx", sheet = "specimen data",skip=1)
#remove columns that don't appear in MarineGEO schema
meio_samples<-meio_samples[,-grep(pattern = "^X",x = names(meio_samples),perl=T)]
#add occurrence IDs to one investigators samples - this has been taken care of now
#meio_samples$occurrenceID[which(is.na(meio_samples$occurrenceID))]<-"UJ" 
#make occurrence IDs unique
#meio_samples$occurrenceID<-make.unique(meio_samples$occurrenceID, sep="_")

Format samples to schema

#change all empty columns from logical to character class
meio_samples[sapply(meio_samples, is.logical)] <- lapply(meio_samples[sapply(meio_samples, is.logical)],  as.character)
meio_samples$basisofRecord<-"specimen" #check with Frey that this is correct
meio_samples$institutionID<-"USNM"
# class(meio_samples$scientificName) #eventually parse this into taxon categories?
# class(meio_samples$taxonRank) #using this
# class(meio_samples$occurrenceID)
# class(meio_samples$catalogNumber)
# class(meio_samples$otherCatalogNumbers)
# class(meio_samples$organismScope)
# class(meio_samples$eventID)
# class(meio_samples$identifiedBy)
# class(meio_samples$individualCount)

Join the event data onto the occurrence data

meio<-left_join(meio_samples,meio_events,by="eventID")

Make A Map

#by individual
meio2<-meio %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(individualCount=sum(individualCount,na.rm = T)) 
#by species
meio3 <- meio %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n())
#richness
meio4<-meio3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
meio5<-left_join(meio2,meio4)
meio_map<-ggmap(dmap) + geom_point(data = meio5, mapping = aes(x = decimalLongitude, y = decimalLatitude, size=individualCount, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Type Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank()) 
meio_map
ggsave(meio_map,filename="./output/meio_map.pdf")

ARMS

Import

arms_samples<-read_excel(path="/Users/eric/google_drive/MarineGEO/ARMS/MarineGEOHI_bioassessment_master-ARMS.xlsx", sheet = "Sample")

Format samples to schema

#change all empty columns from logical to character class
arms_samples[sapply(arms_samples, is.logical)] <- lapply(arms_samples[sapply(arms_samples, is.logical)],  as.character)
# class(arms_samples$occurrenceID)
# class(arms_samples$basisofRecord)
# class(arms_samples$catalogNumber)
# class(arms_samples$otherCatalogNumbers)
# class(arms_samples$organismScope) #were there some slurries too?
# class(arms_samples$eventID)
# class(arms_samples$scientificName) #eventually parse this into taxon categories?
# class(arms_samples$taxonRank) #using this
# class(arms_samples$identifiedBy)
# class(arms_samples$individualCount)
# change NAs for individualCount to 1 for now
arms_samples$individualCount[which(is.na(arms_samples$individualCount))]<-1
arms_samples$institutionID<-"USNM"

Join the event data onto the occurrence data

arms<-left_join(arms_samples,arms_events,by="eventID")

Make A Map

#by individual
arms2<-arms %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(individualCount=sum(individualCount,na.rm = T)) 
#by species
arms3 <- arms %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n())
#richness
arms4<-arms3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
arms5<-left_join(arms2,arms4)
arms_map<-ggmap(dmap) + geom_point(data = arms5, mapping = aes(x = decimalLongitude, y = decimalLatitude, size=individualCount, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Type Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank()) 
arms_map
ggsave(arms_map,filename="./output/arms_map.pdf")

Visual Transects

Import

trans_samples<-read_excel(path="/Users/eric/google_drive/MarineGEO/Transects/bioassessment_KANV.xlsx", sheet = "Sample")
trans_organism_photos<-read_excel(path="/Users/eric/google_drive/MarineGEO/Transects/KANV_photo-vouchers_20170712.xlsx", sheet = "Sheet1")

Format, collapse and merge the media fields

Organism photos

# organism photos
## delete the field to be added later
trans_samples$associatedMedia<-NULL
#pop off the eventID again into its own field
trans_organism_photos$eventID<-sub(pattern="(KANV\\d\\d\\d)_.+",replacement = "\\1", trans_organism_photos$associatedMedia, perl=T)
#pop off the species name into its own field
trans_organism_photos$scientificName<-sub(pattern=".+_(\\d{8})_(\\w+-[a-z]+)_.+", replacement = "\\2", trans_organism_photos$associatedMedia,perl=T)
trans_organism_photos$scientificName<-sub(pattern="-", replacement=" ",x = trans_organism_photos$scientificName)
#pop off the initials of the collector, and replace with full name
trans_organism_photos$identifiedBy<-str_extract(pattern="ZF|RW", string=trans_organism_photos$associatedMedia)
trans_organism_photos$identifiedBy[which(trans_organism_photos$identifiedBy=="ZF")]<-"Zach Foltz"
trans_organism_photos$identifiedBy[which(trans_organism_photos$identifiedBy=="RW")]<-"Ross Whippo"
#use ddply to lump all associatedMedia into a single field, separated by a |
trans_associatedMedia<-ddply(trans_organism_photos, c("eventID","scientificName","identifiedBy"), transform, associatedMedia = paste(associatedMedia, collapse = "|"))
#remove all but the first instance
trans_associatedMedia<-trans_associatedMedia[!duplicated(trans_associatedMedia$associatedMedia),]
trans_samples<-left_join(trans_samples, trans_associatedMedia, by=c("eventID","scientificName","identifiedBy"))

Format samples to schema

#change all empty columns from logical to character class
trans_samples[sapply(trans_samples, is.logical)] <- lapply(trans_samples[sapply(trans_samples, is.logical)],  as.character)
# class(trans_samples$occurrenceID)
# class(trans_samples$basisofRecord)
# class(trans_samples$catalogNumber)
# class(trans_samples$otherCatalogNumbers)
# class(trans_samples$organismScope)
# class(trans_samples$eventID)
# class(trans_samples$scientificName) #eventually parse this into taxon categories?
# class(trans_samples$taxonRank) #using this
# class(trans_samples$identifiedBy)
# class(trans_samples$individualCount)
trans_samples$institutionID<-"USNM"

Join the event data onto the occurrence data

trans<-left_join(trans_samples,trans_events,by="eventID")

Make A Map

#by individual
trans2<-trans %>% group_by(decimalLatitude, decimalLongitude) %>% summarize(individualCount=sum(individualCount,na.rm = T)) 
#by species
trans3 <- trans %>% group_by(scientificName, decimalLatitude, decimalLongitude) %>% summarize(count=n(), individualCount=sum(individualCount,na.rm=T))
#richness
trans4<-trans3 %>% group_by(decimalLatitude,decimalLongitude) %>% summarize(richness=n())
trans5<-left_join(trans2,trans4)
trans_map<-ggmap(dmap) + geom_point(data = trans5, mapping = aes(x = decimalLongitude, y = decimalLatitude, size=individualCount, color=richness)) + scale_color_gradient(low = "green", high="red") + guides(color=guide_colorbar(title="Species Richness",), size=guide_legend(title="Individual Count")) + theme(axis.title=element_blank()) 
trans_map
ggsave(trans_map,filename="./output/trans_map.pdf")

Final Database

Now to join everything into one monster database

a<-full_join(fish,algae)
b<-full_join(a,invert)
c<-full_join(b,meio)
d<-full_join(c,arms)
MarineGEOHI<-full_join(d,trans)
#read in the flat schema
flat_schema<-as.vector(read.csv("flat_schema.csv", header=F, stringsAsFactors = F))
#reduce the joined database to just the columns in the schema, and sort on column order
MarineGEOHI2<-MarineGEOHI[,match(flat_schema, names(MarineGEOHI))]
write.csv(MarineGEOHI2,"./output/MarineGEOHI_data_1.1.csv",row.names = F)
#WriteXLS(c(MarineGEOHI2,as.data.frame(events)),ExcelFileName = "./output/MarineGEOHI_data_1.1.xlsx",SheetNames=c("Events","Samples"))
LS0tCnRpdGxlOiAiTWFyaW5lR0VPIERhdGEgRm9ybWF0dGluZywgU3VtbWFyaXppbmcgYW5kIGpvaW5pbmciCmF1dGhvcjogIkVyaWMgRC4gQ3JhbmRhbGwiCmRhdGU6ICI1LzI5LzIwMTciCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFCikKbGlicmFyeShwbHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdnbWFwKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoc3RyaW5ncikKZmlsZWRpcjwtIn4vZ29vZ2xlX2RyaXZlL01hcmluZUdFTyIKCmJib3g8LWMobGVmdD0tMTU3Ljg1LGJvdHRvbT0gMjEuMzgscmlnaHQ9LTE1Ny43NSwgdG9wPTIxLjU1KQpkbWFwIDwtIGdldF9tYXAobG9jYXRpb24gPSBiYm94LCBtYXB0eXBlID0gInNhdGVsbGl0ZSIsIHNvdXJjZSA9ICJnb29nbGUiKQoKIyB0byBkbzoKCiMgc3BsaXQgc2NpZW50aWZpYyBuYW1lIGludG8gZ2VudXMgYW5kIHNwZWNpZXMgd2hlcmUgYXBwcm9wcmlhdGUKIyBzcC4gY2hhbmdlcyBsb3dlc3Qga25vd24gdG8gZ2VudXMKIyBvcmdhbmlzbVJlbWFya3MgPT0gIkJpc2hvcCIgLSBjaGFuZ2UgaW5zdGl0dXRpb25JRCB0byAiQmlzaG9wIE11c2V1bSIKIyBvcmdhbmlzbVNjb3BlID0gYnVsayBsb3QgaWYgaW5kaXZpZHVhbENvdW50ID4gMQojIGFkZCBvbiBsb2NhdGlvbiBpbmZvIHNwZWNpZmljIHRvIEthbmVvaGUgQmF5CgpgYGAKIyBCdWlsZCBFdmVudHMgRGF0YWJhc2UKCiMjIEZpc2gKYGBge3IgRmlzaCBFdmVudHN9CgpmaXNoX2V2ZW50czwtcmVhZF9leGNlbChwYXRoPSIvVXNlcnMvZXJpYy9nb29nbGVfZHJpdmUvTWFyaW5lR0VPL0Zpc2gvRklTSF9EQVRBXzIxSnVsMjAxNy54bHN4IixzaGVldD0iRXZlbnRzIikKCiMjIyBGb3JtYXQgZXZlbnRzIHRvIHNjaGVtYQoKI2NoYW5nZSBhbGwgZW1wdHkgY29sdW1ucyBmcm9tIGxvZ2ljYWwgdG8gY2hhcmFjdGVyIGNsYXNzCmZpc2hfZXZlbnRzW3NhcHBseShmaXNoX2V2ZW50cywgaXMubG9naWNhbCldIDwtIGxhcHBseShmaXNoX2V2ZW50c1tzYXBwbHkoZmlzaF9ldmVudHMsIGlzLmxvZ2ljYWwpXSwgIGFzLmNoYXJhY3RlcikKCiNjaGFuZ2UgZXZlbnRJRCB0byBqdXN0IHRoZSBLQU5GIHZhbHVlCmZpc2hfZXZlbnRzJGV2ZW50SUQ8LXN0cl9leHRyYWN0KGZpc2hfZXZlbnRzJGV2ZW50SUQsIktBTkZcXGRcXGRcXGQiKQoKI3JvdW5kIHRoZSBsYXQvbG9uZ3MgdG8gZm91ciBkaWdpdHMgKH4gMTBtIHVuY2VydGFpbnR5KQpmaXNoX2V2ZW50cyRkZWNpbWFsTGF0aXR1ZGU8LXJvdW5kKGFzLm51bWVyaWMoZmlzaF9ldmVudHMkZGVjaW1hbExhdGl0dWRlKSxkaWdpdHMgPSA0KQpmaXNoX2V2ZW50cyRkZWNpbWFsTG9uZ2l0dWRlPC1yb3VuZChhcy5udW1lcmljKGZpc2hfZXZlbnRzJGRlY2ltYWxMb25naXR1ZGUpLGRpZ2l0cyA9IDQpCgpmaXNoX2V2ZW50cyRjb29yZGluYXRlVW5jZXJ0YWludHlJbk1ldGVyczwtYXMubnVtZXJpYyhmaXNoX2V2ZW50cyRjb29yZGluYXRlVW5jZXJ0YWludHlJbk1ldGVycykgCgojIGNsYXNzKGZpc2hfZXZlbnRzJGdlb1JlZmVyZW5jZVByb3RvY29sKQojIGNsYXNzKGZpc2hfZXZlbnRzJG1heGltdW1EZXB0aEluTWV0ZXJzKQojIGNsYXNzKGZpc2hfZXZlbnRzJG1pbmltdW1EZXB0aEluTWV0ZXJzKQojIGNsYXNzKGZpc2hfZXZlbnRzJHJlY29yZGVkQnkpIAojIGNsYXNzKGZpc2hfZXZlbnRzJHNhbXBsaW5nUHJvdG9jb2wpICNzb21lIG1pc3NpbmcuIGFzayBEaWFuZSB0byBmaWxsIHRoaXMgaW4KIyBjbGFzcyhmaXNoX2V2ZW50cyRoYWJpdGF0QmlvdGljKQoKI3JlbW92ZSBjYXJyaWFnZSByZXR1cm5zIGZyb20gR2VvbW9ycGhvbG9naWNhbCBab25lCmZpc2hfZXZlbnRzJGhhYml0YXRHZW9tb3JwaG9sb2dpY2FsWm9uZTwtc3RyX3JlcGxhY2VfYWxsKGZpc2hfZXZlbnRzJGhhYml0YXRHZW9tb3JwaG9sb2dpY2FsWm9uZSxwYXR0ZXJuPSJcclxuIixyZXBsYWNlbWVudCA9ICIiKQpmaXNoX2V2ZW50cyRoYWJpdGF0U3Vic3RyYXRlPC1zdHJfcmVwbGFjZV9hbGwoZmlzaF9ldmVudHMkaGFiaXRhdFN1YnN0cmF0ZSxwYXR0ZXJuPSJcclxuIixyZXBsYWNlbWVudCA9ICIiKQoKZmlzaF9ldmVudHMkeWVhcjwtYXMubnVtZXJpYyhmaXNoX2V2ZW50cyR5ZWFyKQpmaXNoX2V2ZW50cyRtb250aDwtbWF0Y2goZmlzaF9ldmVudHMkbW9udGgsbW9udGguYWJiKQpmaXNoX2V2ZW50cyRkYXk8LWFzLm51bWVyaWMoZmlzaF9ldmVudHMkZGF5KQoKI1JlY29tbWVuZGVkIGZpZWxkcwojIGNsYXNzKGZpc2hfZXZlbnRzJGV2ZW50UmVtYXJrcykKIyBjbGFzcyhmaXNoX2V2ZW50cyRsb2NhbGl0eSkKIyBjbGFzcyhmaXNoX2V2ZW50cyRldmVudFJlbWFya3MpCiMgY2xhc3MoZmlzaF9ldmVudHMkdmVyYmF0aW1Db29yZGluYXRlcykKIyBjbGFzcyhmaXNoX2V2ZW50cyRldmVudE1lZGlhKQoKI3JlbW92ZSBlbmRpbmcgdGltZXMgZnJvbSBldmVudFRpbWUgZmllbGQKZmlzaF9ldmVudHMkZXZlbnRUaW1lPC1zdHJfZXh0cmFjdChzdHJpbmc9ZmlzaF9ldmVudHMkZXZlbnRUaW1lLHBhdHRlcm49Il5cXGRcXGQ6XFxkXFxkIikKCmBgYAoKIyMgQWxnYWUKCmBgYHtyIEFsZ2FlIEV2ZW50c30KCmFsZ2FlX2V2ZW50czwtcmVhZF9leGNlbCgiL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9hbGdhZS9NYXJpbmVHRU9ISV9iaW9hc3Nlc3NtZW50X21hc3Rlcl9LQU5BLnhsc3giLCBzaGVldD0iU3RhdGlvbiIpCgojIyMgRm9ybWF0IGV2ZW50cyB0byBzY2hlbWEKCiNjaGFuZ2UgYWxsIGVtcHR5IGNvbHVtbnMgZnJvbSBsb2dpY2FsIHRvIGNoYXJhY3RlciBjbGFzcwphbGdhZV9ldmVudHNbc2FwcGx5KGFsZ2FlX2V2ZW50cywgaXMubG9naWNhbCldIDwtIGxhcHBseShhbGdhZV9ldmVudHNbc2FwcGx5KGFsZ2FlX2V2ZW50cywgaXMubG9naWNhbCldLCAgYXMuY2hhcmFjdGVyKQoKCiNyb3VuZCB0byA0IGRlY2ltYWwgZGlnaXRzICh+MTBtIHVuY2VydGFpbnR5KSBhbmQgbWVha2Ugc3VyZSBsb25naXR1ZGUgaXMgbmVnYXRpdmUKCmFsZ2FlX2V2ZW50cyRkZWNpbWFsTGF0aXR1ZGU8LXJvdW5kKGFzLm51bWVyaWMoYWxnYWVfZXZlbnRzJGRlY2ltYWxMYXRpdHVkZSksZGlnaXRzID0gNCkKYWxnYWVfZXZlbnRzJGRlY2ltYWxMb25naXR1ZGU8LWFicyhyb3VuZChhcy5udW1lcmljKGFsZ2FlX2V2ZW50cyRkZWNpbWFsTG9uZ2l0dWRlKSxkaWdpdHMgPSA0KSkqLTEKCiMgY2xhc3MoYWxnYWVfZXZlbnRzJGV2ZW50SUQpCiMgY2xhc3MoYWxnYWVfZXZlbnRzJGdlb1JlZmVyZW5jZVByb3RvY29sKSAjZ29vZAojIGNsYXNzKGFsZ2FlX2V2ZW50cyRjb29yZGluYXRlVW5jZXJ0YWludHlJbk1ldGVycykgI2dvb2QKIyBjbGFzcyhhbGdhZV9ldmVudHMkbWF4aW11bURlcHRoSW5NZXRlcnMpICNzb21lIG1pc3NpbmcuIGFzayBNZWxpbmRhIHRvIGZpbGwgdGhpcyBpbgojIGNsYXNzKGFsZ2FlX2V2ZW50cyRtaW5pbXVtRGVwdGhJbk1ldGVycykjc29tZSBtaXNzaW5nLiBhc2sgTWVsaW5kYSB0byBmaWxsIHRoaXMgaW4KIyBjbGFzcyhhbGdhZV9ldmVudHMkcmVjb3JkZWRCeSkgI3NvbWUgbWlzc2luZy4gYXNrIE1lbGluZGEgdG8gZmlsbCB0aGlzIGluCiMgY2xhc3MoYWxnYWVfZXZlbnRzJHNhbXBsaW5nUHJvdG9jb2wpICNzb21lIG1pc3NpbmcuIGFzayBNZWxpbmRhIHRvIGZpbGwgdGhpcyBpbgojIGNsYXNzKGFsZ2FlX2V2ZW50cyRgaGFiaXRhdEJpb3RpY2ApCiMgY2xhc3MoYWxnYWVfZXZlbnRzJGBoYWJpdGF0R2VvbW9ycGhvbG9naWNhbFpvbmVgKQojIGNsYXNzKGFsZ2FlX2V2ZW50cyRgaGFiaXRhdFN1YnN0cmF0ZWApCgoKI1JlY29tbWVuZGVkIGZpZWxkcwojIGNsYXNzKGFsZ2FlX2V2ZW50cyRldmVudFJlbWFya3MpCiMgY2xhc3MoYWxnYWVfZXZlbnRzJGxvY2FsaXR5KQojIGNsYXNzKGFsZ2FlX2V2ZW50cyRldmVudFJlbWFya3MpCiMgY2xhc3MoYWxnYWVfZXZlbnRzJHZlcmJhdGltQ29vcmRpbmF0ZXMpCiMgY2xhc3MoYWxnYWVfZXZlbnRzJGV2ZW50TWVkaWEpCgojZm9ybWF0IHRpbWUgY29ycmVjdGx5CmFsZ2FlX2V2ZW50cyRldmVudFRpbWU8LWFzLmNoYXJhY3RlcihwYXJzZV9kYXRlX3RpbWUoYWxnYWVfZXZlbnRzJGV2ZW50VGltZSwgb3JkZXJzPSJ5bWRITVMiLCB0ej0iSFNUIiksZm9ybWF0PSIlSDolTSIpCgoKYGBgCgojIyBNYWNyb2ludmVydGVicmF0ZXMKCmBgYHtyIEludmVydCBFdmVudHN9CgppbnZlcnRfZXZlbnRzPC1yZWFkX2V4Y2VsKHBhdGg9Ii9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9NYXJpbmVHRU8vSW52ZXJ0cy9CS0FORV8wNjMwMTdfRklNUy54bHN4Iiwgc2hlZXQgPSAiU3RhdGlvbiIsIHNraXA9MikKCgoKIyMjIEZvcm1hdCBldmVudHMgdG8gc2NoZW1hCiMgTm90ZTogaW52ZXJ0IGV2ZW50IGRhdGEgbmVlZCBhIGxvdCBvZiBjbGVhbmluZywgaW5jbHVkaW5nIGltcG9ydGluZyBzdGF0aW9ucyBmcm9tIHRoZSBhbGdhZSBhbmQgbWVpb2ZhdW5hIHRlYW0sIGFuZCBtYWtpbmcgbmV3IHN0YXRpb25zIHdpdGggIkEiIG9yICJCIiBhcHBlbmRlZC4gQ3VycmVudGx5IDgzOSBzYW1wbGVzIGRvIG5vdCBoYXZlIHN0YXRpb24gaW5mb3JtYXRpb24gYmVjYXVzZSBvZiB0aGlzLgoKIyByZW1vdmUgZXZlbnQgZmllbGRzIHRoYXQgZG9uJ3QgYXBwZWFyIGluIHRoZSBzY2hlbWEKaW52ZXJ0X2V2ZW50czwtaW52ZXJ0X2V2ZW50c1ssLWdyZXAocGF0dGVybiA9ICJeWCIseCA9IG5hbWVzKGludmVydF9ldmVudHMpLHBlcmw9VCldCgojY2hhbmdlIGFsbCBlbXB0eSBjb2x1bW5zIGZyb20gbG9naWNhbCB0byBjaGFyYWN0ZXIgY2xhc3MKaW52ZXJ0X2V2ZW50c1tzYXBwbHkoaW52ZXJ0X2V2ZW50cywgaXMubG9naWNhbCldIDwtIGxhcHBseShpbnZlcnRfZXZlbnRzW3NhcHBseShpbnZlcnRfZXZlbnRzLCBpcy5sb2dpY2FsKV0sICBhcy5jaGFyYWN0ZXIpCgojcm91bmQgdG8gNCBkZWNpbWFsIGRpZ2l0cyAofjEwbSB1bmNlcnRhaW50eSkgYW5kIG1lYWtlIHN1cmUgbG9uZ2l0dWRlIGlzIG5lZ2F0aXZlCmludmVydF9ldmVudHMkZGVjaW1hbExhdGl0dWRlPC1yb3VuZChhcy5udW1lcmljKGludmVydF9ldmVudHMkZGVjaW1hbExhdGl0dWRlKSxkaWdpdHMgPSA0KQppbnZlcnRfZXZlbnRzJGRlY2ltYWxMb25naXR1ZGU8LWFicyhyb3VuZChhcy5udW1lcmljKGludmVydF9ldmVudHMkZGVjaW1hbExvbmdpdHVkZSksZGlnaXRzID0gNCkpKi0xCgppbnZlcnRfZXZlbnRzJGdlb1JlZmVyZW5jZVByb3RvY29sPC0iR1BTIgppbnZlcnRfZXZlbnRzJGNvb3JkaW5hdGVVbmNlcnRhaW50eUluTWV0ZXJzPC0xMDAKCiMgY2xhc3MoaW52ZXJ0X2V2ZW50cyRtYXhpbXVtRGVwdGhJbk1ldGVycykgI3NvbWUgbWlzc2luZy4gYXNrIEpvaG4gdG8gZmlsbCB0aGlzIGluCiMgY2xhc3MoaW52ZXJ0X2V2ZW50cyRtaW5pbXVtRGVwdGhJbk1ldGVycykjc29tZSBtaXNzaW5nLiBhc2sgSm9obiB0byBmaWxsIHRoaXMgaW4KCiNGb3JtYXQgdGhlIGRhdGUgcHJvcGVybHksIGdldCByaWQgb2YgdGhlICJyYXciIGZpZWxkCmludmVydF9ldmVudHMkZGF5PC1kYXkoaW52ZXJ0X2V2ZW50cyRldmVudERhdGUpCmludmVydF9ldmVudHMkbW9udGg8LW1vbnRoKGludmVydF9ldmVudHMkZXZlbnREYXRlKQppbnZlcnRfZXZlbnRzJHllYXI8LXllYXIoaW52ZXJ0X2V2ZW50cyRldmVudERhdGUpCmludmVydF9ldmVudHMkZXZlbnREYXRlPC1OVUxMCgojIGNsYXNzKGludmVydF9ldmVudHMkcmVjb3JkZWRCeSkgI2dvb2QKIyBjbGFzcyhpbnZlcnRfZXZlbnRzJHNhbXBsaW5nUHJvdG9jb2wpICNzb21lIG1pc3NpbmcuIGFzayBKb2huIHRvIGZpbGwgdGhpcyBpbgojIGNsYXNzKGludmVydF9ldmVudHMkaGFiaXRhdEdlb21vcnBob2xvZ2ljYWxab25lKSAjc29tZSBtaXNzaW5nLiBhc2sgSm9obiB0byBmaWxsIHRoaXMgaW4uICN0aGlzIG5lZWRzIHRvIGJlIGFsaWduZWQgd2l0aCB0aGUgc2NoZW1hCiMgY2xhc3MoaW52ZXJ0X2V2ZW50cyRoYWJpdGF0U3Vic3RyYXRlKSAjIHNvbWUgbWlzc2luZy4gYXNrIEpvaG4gdG8gZmlsbCB0aGlzIGluLiAjdGhpcyBuZWVkcyB0byBiZSBhbGlnbmVkIHdpdGggdGhlIHNjaGVtYQoKCiNSZWNvbW1lbmRlZCBmaWVsZHMKIyBjbGFzcyhpbnZlcnRfZXZlbnRzJGxvY2FsaXR5KQojIGNsYXNzKGludmVydF9ldmVudHMkZXZlbnRSZW1hcmtzKQoKYGBgCgojIyBNZWlvZmF1bmEKCmBgYHtyIE1laW8gRXZlbnRzfQoKbWVpb19ldmVudHM8LXJlYWRfZXhjZWwocGF0aD0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9NZWlvZmF1bmEvSGF3YWlpMjAxN19tZWlvZmF1bmFfTWFyaW5lR0VPLnhsc3giLCBzaGVldCA9ICJzdGF0aW9uIGRhdGEiLCBza2lwPTEpCgojcmVtb3ZlIGNvbHVtbnMgdGhhdCBkb24ndCBhcHBlYXIgaW4gTWFyaW5lR0VPIHNjaGVtYQptZWlvX2V2ZW50czwtbWVpb19ldmVudHNbLC1ncmVwKHBhdHRlcm4gPSAiXlgiLHggPSBuYW1lcyhtZWlvX2V2ZW50cykscGVybD1UKV0KCiMjIyBGb3JtYXQgZXZlbnRzIHRvIHNjaGVtYQoKI01pc3Npbmcgc3RhdGlvbiBLQU5NMDg3ISEhCgojY2hhbmdlIGFsbCBlbXB0eSBjb2x1bW5zIGZyb20gbG9naWNhbCB0byBjaGFyYWN0ZXIgY2xhc3MKbWVpb19ldmVudHNbc2FwcGx5KG1laW9fZXZlbnRzLCBpcy5sb2dpY2FsKV0gPC0gbGFwcGx5KG1laW9fZXZlbnRzW3NhcHBseShtZWlvX2V2ZW50cywgaXMubG9naWNhbCldLCAgYXMuY2hhcmFjdGVyKQoKI3JvdW5kIHRvIDQgZGVjaW1hbCBkaWdpdHMgKH4xMG0gdW5jZXJ0YWludHkpIGFuZCBtZWFrZSBzdXJlIGxvbmdpdHVkZSBpcyBuZWdhdGl2ZQptZWlvX2V2ZW50cyRkZWNpbWFsTGF0aXR1ZGU8LXJvdW5kKGFzLm51bWVyaWMobWVpb19ldmVudHMkZGVjaW1hbExhdGl0dWRlKSxkaWdpdHMgPSA0KQptZWlvX2V2ZW50cyRkZWNpbWFsTG9uZ2l0dWRlPC1hYnMocm91bmQoYXMubnVtZXJpYyhtZWlvX2V2ZW50cyRkZWNpbWFsTG9uZ2l0dWRlKSxkaWdpdHMgPSA0KSkqLTEKCm1laW9fZXZlbnRzJGNvb3JkaW5hdGVVbmNlcnRhaW50eUluTWV0ZXJzPC0xMDAKbWVpb19ldmVudHMkbWluaW11bURlcHRoSW5NZXRlcnM8LWFzLm51bWVyaWMobWVpb19ldmVudHMkbWluaW11bURlcHRoSW5NZXRlcnMpCm1laW9fZXZlbnRzJG1heGltdW1EZXB0aEluTWV0ZXJzPC1hcy5udW1lcmljKG1laW9fZXZlbnRzJG1heGltdW1EZXB0aEluTWV0ZXJzKQoKIyBjbGFzcyhtZWlvX2V2ZW50cyRtYXhpbXVtRGVwdGhJbk1ldGVycykKIyBjbGFzcyhtZWlvX2V2ZW50cyRtaW5pbXVtRGVwdGhJbk1ldGVycykKIyBjbGFzcyhtZWlvX2V2ZW50cyRyZWNvcmRlZEJ5KSAjYXNrIEZyZXlhIHRvIGZvbGxvdyBmb3JtYXQgLSBhZGQgbGFzdCBuYW1lcywgYW5kIHBpcGVzIGJldHdlZW4gbmFtZXMKIyBjbGFzcyhtZWlvX2V2ZW50cyRzYW1wbGluZ1Byb3RvY29sKSAjc29tZSBtaXNzaW5nLiBhc2sgRnJleWEgdG8gZmlsbCB0aGlzIGluCiMgY2xhc3MobWVpb19ldmVudHMkaGFiaXRhdEdlb21vcnBob2xvZ2ljYWxab25lKSAjc29tZSBtaXNzaW5nLiBhc2sgRnJleWEgdG8gZmlsbCB0aGlzIGluCiMgY2xhc3MobWVpb19ldmVudHMkaGFiaXRhdFN1YnN0cmF0ZSkgIyBzb21lIG1pc3NpbmcuIGFzayBGcmV5YSB0byBmaWxsIHRoaXMgaW4KIyBjbGFzcyhtZWlvX2V2ZW50cyRoYWJpdGF0QmlvdGljKQoKI1JlY29tbWVuZGVkIGZpZWxkcwojIGNsYXNzKG1laW9fZXZlbnRzJGxvY2FsaXR5KQojIGNsYXNzKG1laW9fZXZlbnRzJGV2ZW50UmVtYXJrcykKCm1laW9fZXZlbnRzJGRheTwtZGF5KG1laW9fZXZlbnRzJGV2ZW50RGF0ZSkKbWVpb19ldmVudHMkbW9udGg8LW1vbnRoKG1laW9fZXZlbnRzJGV2ZW50RGF0ZSkKbWVpb19ldmVudHMkeWVhcjwteWVhcihtZWlvX2V2ZW50cyRldmVudERhdGUpCm1laW9fZXZlbnRzJGV2ZW50RGF0ZTwtTlVMTAoKI2Zvcm1hdCB0aGUgJF4jJiogdGltZSBjb3JyZWN0bHkKbWVpb19ldmVudHMkZXZlbnRUaW1lPC1mb3JtYXQoLlBPU0lYY3QoODY0MDAqYXMubnVtZXJpYyhtZWlvX2V2ZW50cyRldmVudFRpbWUpLCAiVVRDIiksICIlSDolTSIpCiNtZWlvX2V2ZW50cyRldmVudFRpbWU8LWFzLmNoYXJhY3RlcihwYXJzZV9kYXRlX3RpbWUobWVpb19ldmVudHMkZXZlbnRUaW1lLCBvcmRlcnM9InltZEhNUyIsIHR6PSJIU1QiKSxmb3JtYXQ9IiVIOiVNIikKCm1laW9fZXZlbnRzJGV2ZW50TWVkaWE8LSJOIgoKYGBgCgojIyBBUk1TCgpgYGB7ciBBUk1TIGV2ZW50c30KYXJtc19ldmVudHM8LXJlYWRfZXhjZWwocGF0aD0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9BUk1TL01hcmluZUdFT0hJX2Jpb2Fzc2Vzc21lbnRfbWFzdGVyLUFSTVMueGxzeCIsIHNoZWV0ID0gIlN0YXRpb24iKQoKIyMjIEZvcm1hdCBldmVudHMgdG8gc2NoZW1hCgojY2hhbmdlIGFsbCBlbXB0eSBjb2x1bW5zIGZyb20gbG9naWNhbCB0byBjaGFyYWN0ZXIgY2xhc3MKYXJtc19ldmVudHNbc2FwcGx5KGFybXNfZXZlbnRzLCBpcy5sb2dpY2FsKV0gPC0gbGFwcGx5KGFybXNfZXZlbnRzW3NhcHBseShhcm1zX2V2ZW50cywgaXMubG9naWNhbCldLCAgYXMuY2hhcmFjdGVyKQoKCiNyb3VuZCB0byA0IGRlY2ltYWwgZGlnaXRzICh+MTBtIHVuY2VydGFpbnR5KSBhbmQgbWVha2Ugc3VyZSBsb25naXR1ZGUgaXMgbmVnYXRpdmUKYXJtc19ldmVudHMkZGVjaW1hbExhdGl0dWRlPC1yb3VuZChhcy5udW1lcmljKGFybXNfZXZlbnRzJGRlY2ltYWxMYXRpdHVkZSksZGlnaXRzID0gNCkKYXJtc19ldmVudHMkZGVjaW1hbExvbmdpdHVkZTwtYWJzKHJvdW5kKGFzLm51bWVyaWMoYXJtc19ldmVudHMkZGVjaW1hbExvbmdpdHVkZSksZGlnaXRzID0gNCkpKi0xCmFybXNfZXZlbnRzJGNvb3JkaW5hdGVVbmNlcnRhaW50eUluTWV0ZXJzPC0xMAoKYXJtc19ldmVudHMkbWluaW11bURlcHRoSW5NZXRlcnM8LWFzLm51bWVyaWMoYXJtc19ldmVudHMkbWluaW11bURlcHRoSW5NZXRlcnMpCgojIGNsYXNzKGFybXNfZXZlbnRzJGdlb1JlZmVyZW5jZVByb3RvY29sKQojIGNsYXNzKGFybXNfZXZlbnRzJGV2ZW50SUQpCiMgY2xhc3MoYXJtc19ldmVudHMkbWF4aW11bURlcHRoSW5NZXRlcnMpCiMgY2xhc3MoYXJtc19ldmVudHMkcmVjb3JkZWRCeSkgI2FzayBMYWV0aXRpYSB0byBmb2xsb3cgbmFtZSBmb3JtYXQKIyBjbGFzcyhhcm1zX2V2ZW50cyRzYW1wbGluZ1Byb3RvY29sKQojIGNsYXNzKGFybXNfZXZlbnRzJGhhYml0YXRHZW9tb3JwaG9sb2dpY2FsWm9uZSkKIyBjbGFzcyhhcm1zX2V2ZW50cyRoYWJpdGF0U3Vic3RyYXRlKSAKIyBjbGFzcyhhcm1zX2V2ZW50cyRoYWJpdGF0QmlvdGljKQoKI1JlY29tbWVuZGVkIGZpZWxkcwojIGNsYXNzKGFybXNfZXZlbnRzJGxvY2FsaXR5KQojIGNsYXNzKGFybXNfZXZlbnRzJHllYXIpCiMgY2xhc3MoYXJtc19ldmVudHMkbW9udGgpCiMgY2xhc3MoYXJtc19ldmVudHMkZGF5KQoKYXJtc19ldmVudHMkZXZlbnRNZWRpYTwtIlkiICNzdGlsbCBuZWVkIHRvIGdldCB0aGVzZSBmcm9tIExhZXRpdGlhCgpgYGAKCiMjIFZpc3VhbCBUcmFuc2VjdHMKCmBgYHtyIFRyYW5zZWN0IEV2ZW50c30KdHJhbnNfZXZlbnRzPC1yZWFkX2V4Y2VsKHBhdGg9Ii9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9NYXJpbmVHRU8vVHJhbnNlY3RzL2Jpb2Fzc2Vzc21lbnRfS0FOVi54bHN4Iiwgc2hlZXQgPSAiU3RhdGlvbiIpCgp0cmFuc19ldmVudF9waG90b3M8LXJlYWRfZXhjZWwocGF0aD0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9UcmFuc2VjdHMvS0FOVl9iZW50aGljLXBob3Rvc19maWxlbmFtZXNfMjAxNzA3MTEueGxzeCIsIHNoZWV0ID0gIlNoZWV0MSIpCgojIGV2ZW50IHBob3RvcwojcG9wIG9mZiB0aGUgZXZlbnRJRCBpbnRvIGl0cyBvd24gZmllbGQKdHJhbnNfZXZlbnRfcGhvdG9zJGV2ZW50SUQ8LXN1YihwYXR0ZXJuPSIoS0FOVlxcZFxcZFxcZClfLisiLHJlcGxhY2VtZW50ID0gIlxcMSIsIHRyYW5zX2V2ZW50X3Bob3RvcyRldmVudE1lZGlhLCBwZXJsPVQpCgojdXNlIGRkcGx5IHRvIGx1bXAgYWxsIGV2ZW50TWVkaWEgaW50byBhIHNpbmdsZSBmaWVsZCwgc2VwYXJhdGVkIGJ5IGEgfAp0cmFuc19ldmVudE1lZGlhPC1kZHBseSh0cmFuc19ldmVudF9waG90b3MsICJldmVudElEIiwgdHJhbnNmb3JtLCBldmVudE1lZGlhID0gcGFzdGUoZXZlbnRNZWRpYSwgY29sbGFwc2UgPSAifCIpKQoKI2tlZXAgb25seSB0aGUgZmlyc3QgaW5zdGFuY2Ugb2YgZWFjaCBvY2N1cnJlbmNlSUQKdHJhbnNfZXZlbnRNZWRpYTwtdHJhbnNfZXZlbnRNZWRpYVshZHVwbGljYXRlZCh0cmFuc19ldmVudE1lZGlhJGV2ZW50SUQpLF0KCiNkZWxldGUgb3JpZ2luYWwgZXZlbnRNZWRpYSBjb2x1bW4gYW5kIGpvaW4gb24gdGhlIG5ldyBvbmUKdHJhbnNfZXZlbnRzJGV2ZW50TWVkaWE8LU5VTEwKdHJhbnNfZXZlbnRzPC1sZWZ0X2pvaW4odHJhbnNfZXZlbnRzLCB0cmFuc19ldmVudE1lZGlhLCBieT0iZXZlbnRJRCIpCgoKIyMjIEZvcm1hdCBldmVudHMgdG8gc2NoZW1hCiNjaGFuZ2UgYWxsIGVtcHR5IGNvbHVtbnMgZnJvbSBsb2dpY2FsIHRvIGNoYXJhY3RlciBjbGFzcwp0cmFuc19ldmVudHNbc2FwcGx5KHRyYW5zX2V2ZW50cywgaXMubG9naWNhbCldIDwtIGxhcHBseSh0cmFuc19ldmVudHNbc2FwcGx5KHRyYW5zX2V2ZW50cywgaXMubG9naWNhbCldLCAgYXMuY2hhcmFjdGVyKQojcm91bmQgdG8gNCBkZWNpbWFsIGRpZ2l0cyAofjEwbSB1bmNlcnRhaW50eSkgYW5kIG1lYWtlIHN1cmUgbG9uZ2l0dWRlIGlzIG5lZ2F0aXZlCnRyYW5zX2V2ZW50cyRkZWNpbWFsTGF0aXR1ZGU8LXJvdW5kKGFzLm51bWVyaWModHJhbnNfZXZlbnRzJGRlY2ltYWxMYXRpdHVkZSksZGlnaXRzID0gNCkKdHJhbnNfZXZlbnRzJGRlY2ltYWxMb25naXR1ZGU8LWFicyhyb3VuZChhcy5udW1lcmljKHRyYW5zX2V2ZW50cyRkZWNpbWFsTG9uZ2l0dWRlKSxkaWdpdHMgPSA0KSkqLTEKCnRyYW5zX2V2ZW50cyRtaW5pbXVtRGVwdGhJbk1ldGVyczwtYXMubnVtZXJpYyh0cmFuc19ldmVudHMkbWluaW11bURlcHRoSW5NZXRlcnMpCgojIGNsYXNzKHRyYW5zX2V2ZW50cyRldmVudElEKQojIGNsYXNzKHRyYW5zX2V2ZW50cyRjb29yZGluYXRlVW5jZXJ0YWludHlJbk1ldGVycykKIyBjbGFzcyh0cmFuc19ldmVudHMkbWF4aW11bURlcHRoSW5NZXRlcnMpCiMgY2xhc3ModHJhbnNfZXZlbnRzJHJlY29yZGVkQnkpIAojIGNsYXNzKHRyYW5zX2V2ZW50cyRzYW1wbGluZ1Byb3RvY29sKQojIGNsYXNzKHRyYW5zX2V2ZW50cyRoYWJpdGF0R2VvbW9ycGhvbG9naWNhbFpvbmUpCiMgY2xhc3ModHJhbnNfZXZlbnRzJGhhYml0YXRTdWJzdHJhdGUpCiMgY2xhc3ModHJhbnNfZXZlbnRzJGhhYml0YXRCaW90aWMpCgojUmVjb21tZW5kZWQgZmllbGRzCiMgY2xhc3ModHJhbnNfZXZlbnRzJGxvY2FsaXR5KQojIGNsYXNzKHRyYW5zX2V2ZW50cyR5ZWFyKQojIGNsYXNzKHRyYW5zX2V2ZW50cyRtb250aCkKIyBjbGFzcyh0cmFuc19ldmVudHMkZGF5KQoKdHJhbnNfZXZlbnRzJGV2ZW50VGltZTwtYXMuY2hhcmFjdGVyKHBhcnNlX2RhdGVfdGltZSh0cmFuc19ldmVudHMkZXZlbnRUaW1lLCBvcmRlcnM9InltZEhNUyIsIHR6PSJIU1QiKSxmb3JtYXQ9IiVIOiVNIikKCmBgYAoKIyMgSm9pbiBFdmVudHMKCmBgYHtyIEpvaW4gRXZlbnRzfQpldmVudHM8LWZ1bGxfam9pbihmaXNoX2V2ZW50cyxhbGdhZV9ldmVudHMpCmV2ZW50czwtZnVsbF9qb2luKGV2ZW50cyxpbnZlcnRfZXZlbnRzKQpldmVudHM8LWZ1bGxfam9pbihldmVudHMsbWVpb19ldmVudHMpCmV2ZW50czwtZnVsbF9qb2luKGV2ZW50cyxhcm1zX2V2ZW50cykKZXZlbnRzPC1mdWxsX2pvaW4oZXZlbnRzLHRyYW5zX2V2ZW50cykKCgoKYGBgCiMgQnVpbGQgc2FtcGxlIGRhdGFiYXNlcwoKIyMgRmlzaAoKIyMjIEltcG9ydApgYGB7ciBGaXNoX2ltcG9ydH0KIyBGaXJzdCBnbyB0aHJvdWdoIGFuZCBtYWtlIHN1cmUgYWxsIHN0YXRpb25zIGhhdmUgTGF0L0xvbmdzLCBvciBhcyBtYW55IGFzIHBvc3NpYmxlLiBEZWxldGUgc2Vjb25kYXJ5IGxhdC9sb25ncwojcmVhZCBpbiB0aGUgc2FtcGxlIGRhdGEsIHNraXBwaW5nIGZpcnN0IDMgbGluZXMgb2Ygb3RoZXIgaGVhZGVycy4gRm9ybWF0IGFsbCB0aW1lcyBhcyBoaDptbSBpbiBFeGNlbCwgcGFzdGUgaW50byB0ZXh0d3JhbmdsZXIgaWYgdGhleSBuZWVkIGhvbW9nZW5pemF0aW9uIChpLmUuIG11bHRpcGxlIGZvcm1hdHMgb2YgdGltZXMpCgpmaXNoX3NhbXBsZXM8LXJlYWRfZXhjZWwocGF0aD0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9GaXNoL0ZJU0hfREFUQV8yMUp1bDIwMTcueGxzeCIsc2hlZXQ9IlNhbXBsZXMiKQoKZmlzaF9nZW5ldGljPC1yZWFkX2V4Y2VsKHBhdGg9Ii9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9NYXJpbmVHRU8vRmlzaC9GSVNIX0RBVEFfMjFKdWwyMDE3Lnhsc3giLHNoZWV0PSJHZW5ldGljIHNhbXBsZXMiKQojdGhlc2UgY29tbWFuZHMgYXBwbHkgdG8gdGhlIG9yaWdpbmFsIGZpc2gtZ3JvdXAgdGVtcGxhdGUKI3JlbW92ZSBjb2x1bW5zIHdpdGhvdXQgbWFwcGVkIER3QyB0ZXJtcyBtYXBwZWQKI2Zpc2hfc2FtcGxlczwtZmlzaF9zYW1wbGVzWywtZ3JlcChwYXR0ZXJuID0gIl5YIix4ID0gbmFtZXMoZmlzaF9zYW1wbGVzKSxwZXJsPVQpXQojZmlzaF9ldmVudHM8LWZpc2hfZXZlbnRzWywtZ3JlcChwYXR0ZXJuID0gIl5YIix4ID0gbmFtZXMoZmlzaF9ldmVudHMpLHBlcmw9VCldCgojcmVtb3ZlIHJlY29yZHMgd2l0aG91dCBvY2N1cnJlbmNlSURzICh0ZW1wIGJlZm9yZSBmaW5hbCBkYXRhc2V0KQojZmlzaF9zYW1wbGVzPC1maXNoX3NhbXBsZXNbLXdoaWNoKGlzLm5hKGZpc2hfc2FtcGxlcyRvY2N1cnJlbmNlSUQpKSxdCiN0cmFuc2xhdGUgZmllbGRJRHMgdG8gZXZlbnRJRHMKI2Zpc2hfc2FtcGxlcyRldmVudElEPC1nc3ViKCJMUlAgMTctIiwiS0FORjAiLGZpc2hfc2FtcGxlcyRldmVudElEKQojdXNlIGRkcGx5IHRvIGx1bXAgYWxsIG1hdGVyaWFsU2FtcGxlSURzIGludG8gYSBzaW5nbGUgZmllbGQsIHNlcGFyYXRlZCBieSBhIHwKI2Zpc2hfc2FtcGxlczwtZGRwbHkoZmlzaF9zYW1wbGVzLCAib2NjdXJyZW5jZUlEIiwgdHJhbnNmb3JtLCBtYXRlcmlhbFNhbXBsZUlEID0gI3Bhc3RlKG1hdGVyaWFsU2FtcGxlSUQsIGNvbGxhcHNlID0gInwiKSkKI2tlZXAgb25seSB0aGUgZmlyc3QgaW5zdGFuY2Ugb2YgZWFjaCBvY2N1cnJlbmNlSUQKI2Zpc2hfc2FtcGxlczwtZmlzaF9zYW1wbGVzWyFkdXBsaWNhdGVkKGZpc2hfc2FtcGxlcyRvY2N1cnJlbmNlSUQpLF0KYGBgCgoKIyMjIEZvcm1hdCBzYW1wbGVzIHRvIHNjaGVtYQoKYGBge3IgZm9ybWF0IGZpc2ggc2FtcGxlc30KI2NoYW5nZSBhbGwgZW1wdHkgY29sdW1ucyBmcm9tIGxvZ2ljYWwgdG8gY2hhcmFjdGVyIGNsYXNzCmZpc2hfc2FtcGxlc1tzYXBwbHkoZmlzaF9zYW1wbGVzLCBpcy5sb2dpY2FsKV0gPC0gbGFwcGx5KGZpc2hfc2FtcGxlc1tzYXBwbHkoZmlzaF9zYW1wbGVzLCBpcy5sb2dpY2FsKV0sICBhcy5jaGFyYWN0ZXIpCgojRml4IHRoZSBldmVudElEcwpmaXNoX3NhbXBsZXMkZXZlbnRJRDwtc3RyX2V4dHJhY3QoZmlzaF9zYW1wbGVzJGV2ZW50SUQsIktBTkZcXGRcXGRcXGQiKQoKCmZpc2hfc2FtcGxlcyRvdGhlckNhdGFsb2dOdW1iZXJzPC1OVUxMICMgZHJvcCB0aGlzIGZvciBub3cgLSBpdCB3aWxsIGJlIHJlcGxhY2VkIGJ5IGZpc2hfYmlvcmVwIGJlbG93CgojIGNsYXNzKGZpc2hfc2FtcGxlc1ssd2hpY2goc2FwcGx5KGZpc2hfc2FtcGxlcywgaXMubG9naWNhbCkpXSk8LSJjaGFyYWN0ZXIiCiMgY2xhc3MoZmlzaF9zYW1wbGVzJG9jY3VycmVuY2VJRCkKIyBjbGFzcyhmaXNoX3NhbXBsZXMkYmFzaXNvZlJlY29yZCkKIyBjbGFzcyhmaXNoX3NhbXBsZXMkY2F0YWxvZ051bWJlcik8LSJjaGFyYWN0ZXIiCiMgY2xhc3MoZmlzaF9zYW1wbGVzJG9yZ2FuaXNtU2NvcGUpCiMgY2xhc3MoZmlzaF9zYW1wbGVzJGV2ZW50SUQpCiMgY2xhc3MoZmlzaF9zYW1wbGVzJHNjaWVudGlmaWNOYW1lKSAjZXZlbnR1YWxseSBwYXJzZSB0aGlzIGludG8gdGF4b24gY2F0ZWdvcmllcz8KIyBjbGFzcyhmaXNoX3NhbXBsZXMkdGF4b25SYW5rKSAjdXNpbmcgdGhpcwojIGNsYXNzKGZpc2hfc2FtcGxlcyRpbmRpdmlkdWFsQ291bnQpCiMgY2xhc3MoZmlzaF9zYW1wbGVzJGluc3RpdHV0aW9uSUQpCgojIG1ha2UgaWRlbnRpZmllZEJ5IGdvIGZpcnN0bmFtZSBsYXN0bmFtZQpmaXNoX3NhbXBsZXMkaWRlbnRpZmllZEJ5PC1zdHJfcmVwbGFjZShmaXNoX3NhbXBsZXMkaWRlbnRpZmllZEJ5LCBwYXR0ZXJuPSIoXFx3KyksICguKykiLCByZXBsYWNlbWVudD0iXFwyIFxcMSIpCgpmaXNoX3NhbXBsZXMkY2F0YWxvZ051bWJlcjwtYXMuY2hhcmFjdGVyKGZpc2hfc2FtcGxlcyRjYXRhbG9nTnVtYmVyKQoKYGBgCgojIyMgRm9ybWF0IHRoZSBiaW9yZXBvc2l0b3J5IGluZm8KYGBge3IgZmlzaCBiaW9yZXBvc2l0b3J5fQpjb2xuYW1lcyhmaXNoX2dlbmV0aWMpWzVdPC0iQmlvcmVwb3NpdG9yeUlEIgpjb2xuYW1lcyhmaXNoX2dlbmV0aWMpWzZdPC0idGlzc3VlTm90ZXMiCmNvbG5hbWVzKGZpc2hfZ2VuZXRpYylbMl08LSJvY2N1cnJlbmNlSUQiCiN1c2UgZGRwbHkgdG8gbHVtcCBhbGwgbWF0ZXJpYWxTYW1wbGVJRHMgaW50byBhIHNpbmdsZSBmaWVsZCwgc2VwYXJhdGVkIGJ5IGEgfApmaXNoX2Jpb3JlcDwtZGRwbHkoZmlzaF9nZW5ldGljLCAib2NjdXJyZW5jZUlEIiwgdHJhbnNmb3JtLCBvdGhlckNhdGFsb2dOdW1iZXJzID0gcGFzdGUoQmlvcmVwb3NpdG9yeUlELCBjb2xsYXBzZSA9ICJ8IiksIHRpc3N1ZU5vdGVzID0gcGFzdGUodGlzc3VlTm90ZXMsIGNvbGxhcHNlPSJ8IikpCiNrZWVwIG9ubHkgdGhlIGZpcnN0IGluc3RhbmNlIG9mIGVhY2ggb2NjdXJyZW5jZUlECmZpc2hfYmlvcmVwPC1maXNoX2Jpb3JlcFshZHVwbGljYXRlZChmaXNoX2Jpb3JlcCRvdGhlckNhdGFsb2dOdW1iZXJzKSxdCmZpc2hfYmlvcmVwJG90aGVyQ2F0YWxvZ051bWJlcnM8LWFzLmNoYXJhY3RlcihmaXNoX2Jpb3JlcCRvdGhlckNhdGFsb2dOdW1iZXJzKQpgYGAKCiMjIyBKb2luIHRoZSBldmVudCBkYXRhIG9udG8gdGhlIG9jY3VycmVuY2UgZGF0YQoKYGBge3IgZmlzaCBqb2lufQoKI2ZpcnN0IGpvaW4gdGhlIGJpb3JlcCBudW1iZXJzIHRvIHRoaXMgZGF0YQpmaXNoX3NhbXBsZXM8LWxlZnRfam9pbihmaXNoX3NhbXBsZXMsZmlzaF9iaW9yZXBbLGMoMiw2LDcpXSxieT0ib2NjdXJyZW5jZUlEIikKI25vdyBqb2luIHNhbXBsZXMgYW5kIGV2ZW50cwpmaXNoPC1sZWZ0X2pvaW4oZmlzaF9zYW1wbGVzLGV2ZW50cyxieT0iZXZlbnRJRCIpCgoKYGBgCgojIyMgTWFrZSBhIE1hcAoKYGBge3IgZmlzaCBtYXBzfQojb3B0aW9uYWxseSBtYWtlIGl0IGZyb20gdGhlIHBvaW50cyBwcm92aWRlZAojYmJveDwtbWFrZV9iYm94KGxvbj1maXNoMiRkZWNpbWFsTG9uZ2l0dWRlLGxhdD1maXNoMiRkZWNpbWFsTGF0aXR1ZGUpCiNieSBpbmRpdmlkdWFsCmZpc2gyPC1maXNoICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsIGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUoY291bnQ9bigpKSAKCiNieSBzcGVjaWVzCmZpc2gzIDwtIGZpc2ggJT4lIGdyb3VwX2J5KHNjaWVudGlmaWNOYW1lLCBkZWNpbWFsTGF0aXR1ZGUsIGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUoY291bnQ9bigpKQoKI3JpY2huZXNzCmZpc2g0PC1maXNoMyAlPiUgZ3JvdXBfYnkoZGVjaW1hbExhdGl0dWRlLGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUocmljaG5lc3M9bigpKQoKZmlzaDY8LWxlZnRfam9pbihmaXNoMixmaXNoNCkKCgpmaXNoX21hcDwtZ2dtYXAoZG1hcCkgKyBnZW9tX3BvaW50KGRhdGEgPSBmaXNoNiwgbWFwcGluZyA9IGFlcyh4ID0gZGVjaW1hbExvbmdpdHVkZSwgeSA9IGRlY2ltYWxMYXRpdHVkZSwgc2l6ZT1jb3VudCwgY29sb3I9cmljaG5lc3MpKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJncmVlbiIsIGhpZ2g9InJlZCIpICsgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlPSJTcGVjaWVzIFJpY2huZXNzIiwpLCBzaXplPWd1aWRlX2xlZ2VuZCh0aXRsZT0iSW5kaXZpZHVhbCBDb3VudCIpKSArIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpKQoKZmlzaF9tYXAKCgpnZ3NhdmUoZmlzaF9tYXAsZmlsZW5hbWU9Ii4vb3V0cHV0L2Zpc2hfbWFwLnBkZiIpCgpgYGAKCgojIyBBbGdhZQoKIyMjIEltcG9ydApgYGB7ciBBbGdhZSBpbXBvcnR9CiNlZGl0IGV2ZW50SURzIGZvciBjYXBpdGFsaXphdGlvbgoKYWxnYWVfc2FtcGxlczwtcmVhZF9leGNlbCgiL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9hbGdhZS9NYXJpbmVHRU9ISV9iaW9hc3Nlc3NtZW50X21hc3Rlcl9LQU5BLnhsc3giLCBzaGVldD0iU2FtcGxlIikKCmBgYAoKIyMjIEZvcm1hdCBzYW1wbGVzIHRvIHNjaGVtYQoKYGBge3IgZm9ybWF0IGFsZ2FlIHNhbXBsZXN9CiNjaGFuZ2UgYWxsIGVtcHR5IGNvbHVtbnMgZnJvbSBsb2dpY2FsIHRvIGNoYXJhY3RlciBjbGFzcwphbGdhZV9zYW1wbGVzW3NhcHBseShhbGdhZV9zYW1wbGVzLCBpcy5sb2dpY2FsKV0gPC0gbGFwcGx5KGFsZ2FlX3NhbXBsZXNbc2FwcGx5KGFsZ2FlX3NhbXBsZXMsIGlzLmxvZ2ljYWwpXSwgIGFzLmNoYXJhY3RlcikKCiMgY2xhc3MoYWxnYWVfc2FtcGxlcyRvY2N1cnJlbmNlSUQpCiMgY2xhc3MoYWxnYWVfc2FtcGxlcyRjYXRhbG9nTnVtYmVyKQojIGNsYXNzKGFsZ2FlX3NhbXBsZXMkb3RoZXJDYXRhbG9nTnVtYmVycykKIyBjbGFzcyhhbGdhZV9zYW1wbGVzJG9yZ2FuaXNtU2NvcGUpCiMgY2xhc3MoYWxnYWVfc2FtcGxlcyRldmVudElEKQojIGNsYXNzKGFsZ2FlX3NhbXBsZXMkc2NpZW50aWZpY05hbWUpICNldmVudHVhbGx5IHBhcnNlIHRoaXMgaW50byB0YXhvbiBjYXRlZ29yaWVzPwojIGNsYXNzKGFsZ2FlX3NhbXBsZXMkdGF4b25SYW5rKSAjIE1lbGluZGEgbmVlZHMgdG8gcG9wdWxhdGUgdGhpcy4uLgojIGNsYXNzKGFsZ2FlX3NhbXBsZXMkaWRlbnRpZmllZEJ5KQojIGNsYXNzKGFsZ2FlX3NhbXBsZXMkaW5kaXZpZHVhbENvdW50KQoKYWxnYWVfc2FtcGxlcyRiYXNpc29mUmVjb3JkPC0ic3BlY2ltZW4iCmFsZ2FlX3NhbXBsZXMkaW5zdGl0dXRpb25JRDwtIlVTTk0iCgoKCmBgYAoKCgoKIyMjIEpvaW4gdGhlIGV2ZW50IGRhdGEgb250byB0aGUgb2NjdXJyZW5jZSBkYXRhCgpgYGB7ciBqb2luIGFsZ2FlfQoKYWxnYWU8LWxlZnRfam9pbihhbGdhZV9zYW1wbGVzLGV2ZW50cyxieT0iZXZlbnRJRCIpCgpgYGAKCiMjIyBNYWtlIEEgTWFwCmBgYHtyIGFsZ2FlIG1hcHN9CgoKI2J5IGluZGl2aWR1YWwKYWxnYWUyPC1hbGdhZSAlPiUgZ3JvdXBfYnkoZGVjaW1hbExhdGl0dWRlLCBkZWNpbWFsTG9uZ2l0dWRlKSAlPiUgc3VtbWFyaXplKGNvdW50PW4oKSkgCgojYnkgc3BlY2llcwphbGdhZTMgPC0gYWxnYWVbLXdoaWNoKGFsZ2FlJHNjaWVudGlmaWNOYW1lPT0iPyIpLF0gJT4lIGdyb3VwX2J5KHNjaWVudGlmaWNOYW1lLCBkZWNpbWFsTGF0aXR1ZGUsIGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUoY291bnQ9bigpKQoKI3JpY2huZXNzCmFsZ2FlNDwtYWxnYWUzICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShyaWNobmVzcz1uKCkpCgphbGdhZTU8LWxlZnRfam9pbihhbGdhZTIsYWxnYWU0KQoKI2FsZ2FlNTwtYWxnYWU1W3doaWNoKGlzLm5hKGFsZ2FlNSRkZWNpbWFsTGF0aXR1ZGUpKSxdCiNhbGdhZTU8LWFsZ2FlNVstd2hpY2goYWxnYWU1JHNjaWVudGlmaWNOYW1lPT0iPyIpLF0KCmFsZ2FlNVs0LDRdPC0xCmFsZ2FlNVsxMSw0XTwtMgpleHRyYTwtYWxnYWU1WzMzLF0KYWxnYWU1PC1hbGdhZTVbLTMzLF0gI3JlbW92ZSBvdXRsaWVyCgoKYWxnYWVfbWFwPC1nZ21hcChkbWFwKSArIGdlb21fcG9pbnQoZGF0YSA9IGFsZ2FlNSwgbWFwcGluZyA9IGFlcyh4ID0gZGVjaW1hbExvbmdpdHVkZSwgeSA9IGRlY2ltYWxMYXRpdHVkZSwgc2l6ZT1jb3VudCwgY29sb3I9cmljaG5lc3MpKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJncmVlbiIsIGhpZ2g9InJlZCIpICsgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlPSJUeXBlIFJpY2huZXNzIiwpLCBzaXplPWd1aWRlX2xlZ2VuZCh0aXRsZT0iSW5kaXZpZHVhbCBDb3VudCIpKSArIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpKSArIGdlb21fcG9pbnQoZGF0YT1leHRyYSwgbWFwcGluZz1hZXMoeCA9IGRlY2ltYWxMb25naXR1ZGUsIHkgPSBkZWNpbWFsTGF0aXR1ZGUsIHNpemU9MzAsIGNvbG9yPTMwKSkKI2FkZCBvdXRsaWVyIGJhY2sgaW4gYXMgYSByZWQgZG90IHNpemU9MzAKCmFsZ2FlX21hcAoKZ2dzYXZlKGFsZ2FlX21hcCxmaWxlbmFtZT0iLi9vdXRwdXQvYWxnYWVfbWFwLnBkZiIpCmBgYAoKIyMgTWFjcm9pbnZlcnRlYnJhdGVzCgojIyMgSW1wb3J0CmBgYHtyIGludmVydHMgaW1wb3J0fQppbnZlcnRfc2FtcGxlczwtcmVhZF9leGNlbChwYXRoPSIvVXNlcnMvZXJpYy9nb29nbGVfZHJpdmUvTWFyaW5lR0VPL0ludmVydHMvQktBTkVfMDYzMDE3X0ZJTVMueGxzeCIsIHNoZWV0ID0gIlNwZWNpbWVuIixza2lwPTMpCgojc3BvbmdlcyB3aWxsIGJlIGxvYWRlZCBoZXJlLCBjbGVhbmVkIHVwLCBhbmQgdGhlbiBqb2luZWQgd2l0aCB0aGUgcmVzdCBvZiB0aGUgaW52ZXJ0cwpzcG9uZ2Vfc2FtcGxlczwtcmVhZF9leGNlbChwYXRoPSIvVXNlcnMvZXJpYy9nb29nbGVfZHJpdmUvTWFyaW5lR0VPL1Nwb25nZXMvVklDRU5URV9CSU9CTElUWjIwMTdfU1BPTkdFTUVUQURBVEFfRklNUy54bHN4Iiwgc2hlZXQgPSAiU2hlZXQxIixza2lwPTEpCgojcmVtb3ZlIGNvbHVtbnMgdGhhdCBkb24ndCBhcHBlYXIgaW4gTWFyaW5lR0VPIHNjaGVtYQppbnZlcnRfc2FtcGxlczwtaW52ZXJ0X3NhbXBsZXNbLC1ncmVwKHBhdHRlcm4gPSAiXlgiLHggPSBuYW1lcyhpbnZlcnRfc2FtcGxlcykscGVybD1UKV0Kc3BvbmdlX3NhbXBsZXM8LXNwb25nZV9zYW1wbGVzWywtZ3JlcChwYXR0ZXJuID0gIl5YIix4ID0gbmFtZXMoc3BvbmdlX3NhbXBsZXMpLHBlcmw9VCldCgojcmVtb3ZlIHJlY29yZHMgd2l0aG91dCBvY2N1cnJlbmNlSURzICh0ZW1wIGJlZm9yZSBmaW5hbCBkYXRhc2V0KQppbnZlcnRfc2FtcGxlczwtaW52ZXJ0X3NhbXBsZXNbLXdoaWNoKGlzLm5hKGludmVydF9zYW1wbGVzJHNjaWVudGlmaWNOYW1lKSksXQpzcG9uZ2Vfc2FtcGxlczwtc3BvbmdlX3NhbXBsZXNbLXdoaWNoKGlzLm5hKHNwb25nZV9zYW1wbGVzJHNjaWVudGlmaWNOYW1lKSksXQoKI2NoYW5nZSBhbGwgZW1wdHkgY29sdW1ucyBmcm9tIGxvZ2ljYWwgdG8gY2hhcmFjdGVyIGNsYXNzCmludmVydF9zYW1wbGVzW3NhcHBseShpbnZlcnRfc2FtcGxlcywgaXMubG9naWNhbCldIDwtIGxhcHBseShpbnZlcnRfc2FtcGxlc1tzYXBwbHkoaW52ZXJ0X3NhbXBsZXMsIGlzLmxvZ2ljYWwpXSwgIGFzLmNoYXJhY3RlcikKCgpzcG9uZ2Vfc2FtcGxlc1tzYXBwbHkoc3BvbmdlX3NhbXBsZXMsIGlzLmxvZ2ljYWwpXSA8LSBsYXBwbHkoc3BvbmdlX3NhbXBsZXNbc2FwcGx5KHNwb25nZV9zYW1wbGVzLCBpcy5sb2dpY2FsKV0sICBhcy5jaGFyYWN0ZXIpCgpzcG9uZ2Vfc2FtcGxlcyRwaHlsdW1bd2hpY2goaXMubmEoc3BvbmdlX3NhbXBsZXMkcGh5bHVtKSldPC0iUG9yaWZlcmEiCnNwb25nZV9zYW1wbGVzJGV2ZW50SUQ8LXN0cl9yZXBsYWNlKHNwb25nZV9zYW1wbGVzJGV2ZW50SUQscGF0dGVybj0iLSIsIHJlcGxhY2VtZW50PSIiKQoKCmludmVydF9zYW1wbGVzPC1mdWxsX2pvaW4oaW52ZXJ0X3NhbXBsZXMsc3BvbmdlX3NhbXBsZXMpCmBgYAoKIyMjIFRheG9ub21pemUKClRoaXMgY29kZSB3aWxsIHBvcHVsYXRlIGB0YXhvblJhbmtgIHdpdGggdGhlIGxvd2VzdCBrbm93biB0YXhvbm9taWMgY2F0ZWdvcnkKCmBgYHtyIEludmVydHMgVGF4b25vbWl6ZX0KCmludmVydF9zYW1wbGVzJHRheG9uUmFua1t3aGljaCghaXMubmEoaW52ZXJ0X3NhbXBsZXMkcGh5bHVtKSldPC0icGh5bHVtIgppbnZlcnRfc2FtcGxlcyR0YXhvblJhbmtbd2hpY2goIWlzLm5hKGludmVydF9zYW1wbGVzJGNsYXNzKSldPC0iY2xhc3MiCmludmVydF9zYW1wbGVzJHRheG9uUmFua1t3aGljaCghaXMubmEoaW52ZXJ0X3NhbXBsZXMkc3ViY2xhc3MpKV08LSJzdWJjbGFzcyIKaW52ZXJ0X3NhbXBsZXMkdGF4b25SYW5rW3doaWNoKCFpcy5uYShpbnZlcnRfc2FtcGxlcyRvcmRlcikpXTwtIm9yZGVyIgppbnZlcnRfc2FtcGxlcyR0YXhvblJhbmtbd2hpY2goIWlzLm5hKGludmVydF9zYW1wbGVzJHN1Ym9yZGVyKSldPC0ic3Vib3JkZXIiCmludmVydF9zYW1wbGVzJHRheG9uUmFua1t3aGljaCghaXMubmEoaW52ZXJ0X3NhbXBsZXMkc3VwZXJmYW1pbHkpKV08LSJzdXBlcmZhbWlseSIKaW52ZXJ0X3NhbXBsZXMkdGF4b25SYW5rW3doaWNoKCFpcy5uYShpbnZlcnRfc2FtcGxlcyRmYW1pbHkpKV08LSJmYW1pbHkiCmludmVydF9zYW1wbGVzJHRheG9uUmFua1t3aGljaCghaXMubmEoaW52ZXJ0X3NhbXBsZXMkc3ViZmFtaWx5KSldPC0ic3ViZmFtaWx5IgppbnZlcnRfc2FtcGxlcyR0YXhvblJhbmtbd2hpY2goIWlzLm5hKGludmVydF9zYW1wbGVzJGdlbnVzKSldPC0iZ2VudXMiCmludmVydF9zYW1wbGVzJHRheG9uUmFua1t3aGljaCghaXMubmEoaW52ZXJ0X3NhbXBsZXMkc3BlY2llcykpXTwtInNwZWNpZXMiCmludmVydF9zYW1wbGVzJHRheG9uUmFua1tncmVwKCJzcFxcLiIsaW52ZXJ0X3NhbXBsZXMkc3BlY2llcyldPC0iZ2VudXMiCgoKCmBgYAoKCiMjIyBGb3JtYXQgc2FtcGxlcyB0byBzY2hlbWEKCmBgYHtyIGZvcm1hdCBpbnZlcnQgc2FtcGxlc30KI2NoYW5nZSBhbGwgZW1wdHkgY29sdW1ucyBmcm9tIGxvZ2ljYWwgdG8gY2hhcmFjdGVyIGNsYXNzIG1vdmVkIHRoaXMgdXAKI2ludmVydF9zYW1wbGVzW3NhcHBseShpbnZlcnRfc2FtcGxlcywgaXMubG9naWNhbCldIDwtICNsYXBwbHkoaW52ZXJ0X3NhbXBsZXNbc2FwcGx5KGludmVydF9zYW1wbGVzLCBpcy5sb2dpY2FsKV0sICBhcy5jaGFyYWN0ZXIpCgojIGNsYXNzKGludmVydF9zYW1wbGVzJG9jY3VycmVuY2VJRCkKIyBjbGFzcyhpbnZlcnRfc2FtcGxlcyRzY2llbnRpZmljTmFtZSkgI2V2ZW50dWFsbHkgcGFyc2UgdGhpcyBpbnRvIHRheG9uIGNhdGVnb3JpZXM/CiMgY2xhc3MoaW52ZXJ0X3NhbXBsZXMkdGF4b25SYW5rKSAjdXNpbmcgdGhpcwoKaW52ZXJ0X3NhbXBsZXMkYmFzaXNPZlJlY29yZDwtInNwZWNpbWVuIgppbnZlcnRfc2FtcGxlcyRvcmdhbmlzbVNjb3BlPC0ib3JnYW5pc20iCgojcmVtb3ZlIGV2ZW50SURzIHRoYXQgaGF2ZSB0d28gcG9zc2liaWxpdGllcywgYXNzdW1lIGl0IGlzIHRoZSBmaXJzdCBvbmUgZm9yIG5vdwppbnZlcnRfc2FtcGxlcyRldmVudElEPC1nc3ViKHBhdHRlcm49IihcXHcpIG9yIFxcdyIscmVwbGFjZW1lbnQ9IlxcMSIseD0gaW52ZXJ0X3NhbXBsZXMkZXZlbnRJRCxwZXJsPVQpCgojcmVtb3ZlIHRoZSBBLEIsQyBldGMuIGZyb20gdGhlIGVuZHMgb2YgZXZlbnRJRHMgdW50aWwgdGhlIElaIHRlYW0gZml4ZXMgdGhlbSB1cCB0byBiZSBtZWFuaW5nZnVsCmludmVydF9zYW1wbGVzJGV2ZW50SUQ8LXN0cl9yZXBsYWNlKHN0cmluZz1pbnZlcnRfc2FtcGxlcyRldmVudElELCBwYXR0ZXJuPSIoS0FOXFx3XFxkXFxkXFxkKVtBLVpdIixyZXBsYWNlbWVudD0iXFwxIikKCiNmaXggYXJtcyBldmVudElEcwppbnZlcnRfc2FtcGxlcyRldmVudElEW2dyZXAocGF0dGVybj0iS0FORU8iLGludmVydF9zYW1wbGVzJGV2ZW50SUQpXTwtc3RyX3JlcGxhY2Uoc3RyaW5nPWludmVydF9zYW1wbGVzJGV2ZW50SURbZ3JlcChwYXR0ZXJuPSJLQU5FTyIsaW52ZXJ0X3NhbXBsZXMkZXZlbnRJRCldLHBhdHRlcm49IktBTkVPXFxkKFxcZFxcZCkiLCByZXBsYWNlbWVudD0iS0FORU9fMjAxN19BUk1TXFwxIikKCgppbnZlcnRfc2FtcGxlcyRpZGVudGlmaWVkQnk8LSJQYXVsYXksIEd1c3RhdiIgIyBmb3Igbm93LiBkb24ndCBrbm93IGlmIHRoZXkga2VwdCB0aGlzIGluZm8KI2Fzc3VtZSB0aGF0IGJsYW5rIGNvdW50cyBoYWQgMSBpbmRpdmlkdWFsIGZvciBub3cKaW52ZXJ0X3NhbXBsZXMkaW5kaXZpZHVhbENvdW50W2lzLm5hKGludmVydF9zYW1wbGVzJGluZGl2aWR1YWxDb3VudCldPC0xCmludmVydF9zYW1wbGVzJGluc3RpdHV0aW9uSUQ8LSJGTE1OSCIKCgoKYGBgCgojIyMgSm9pbiB0aGUgZXZlbnQgZGF0YSBvbnRvIHRoZSBvY2N1cnJlbmNlIGRhdGEKCmBgYHtyIGludmVydCBqb2lufQppbnZlcnQ8LWxlZnRfam9pbihpbnZlcnRfc2FtcGxlcyxldmVudHMsYnk9ImV2ZW50SUQiKQpgYGAKCiMjIyBNYWtlIEEgTWFwCmBgYHtyIGludmVydCBtYXBzfQojYnkgaW5kaXZpZHVhbAppbnZlcnQyPC1pbnZlcnQgJT4lIGdyb3VwX2J5KGRlY2ltYWxMYXRpdHVkZSwgZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShpbmRpdmlkdWFsQ291bnQ9c3VtKGluZGl2aWR1YWxDb3VudCxuYS5ybSA9IFQpKSAKCiNieSBzcGVjaWVzCmludmVydDMgPC0gaW52ZXJ0ICU+JSBncm91cF9ieShzY2llbnRpZmljTmFtZSwgZGVjaW1hbExhdGl0dWRlLCBkZWNpbWFsTG9uZ2l0dWRlKSAlPiUgc3VtbWFyaXplKGNvdW50PW4oKSkKCiNyaWNobmVzcwppbnZlcnQ0PC1pbnZlcnQzICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShyaWNobmVzcz1uKCkpCgppbnZlcnQ1PC1sZWZ0X2pvaW4oaW52ZXJ0MixpbnZlcnQ0KQoKCgoKaW52ZXJ0X21hcDwtZ2dtYXAoZG1hcCkgKyBnZW9tX3BvaW50KGRhdGEgPSBpbnZlcnQ1Wy1jKGxlbmd0aChpbnZlcnQ1JHJpY2huZXNzKS0xLGxlbmd0aChpbnZlcnQ1JHJpY2huZXNzKSksXSwgbWFwcGluZyA9IGFlcyh4ID0gZGVjaW1hbExvbmdpdHVkZSwgeSA9IGRlY2ltYWxMYXRpdHVkZSwgc2l6ZT1pbmRpdmlkdWFsQ291bnQsIGNvbG9yPXJpY2huZXNzKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiZ3JlZW4iLCBoaWdoPSJyZWQiKSArIGd1aWRlcyhjb2xvcj1ndWlkZV9jb2xvcmJhcih0aXRsZT0iVHlwZSBSaWNobmVzcyIsKSwgc2l6ZT1ndWlkZV9sZWdlbmQodGl0bGU9IkluZGl2aWR1YWwgQ291bnQiKSkgKyB0aGVtZShheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgCgppbnZlcnRfbWFwCgpnZ3NhdmUoaW52ZXJ0X21hcCxmaWxlbmFtZT0iLi9vdXRwdXQvaW52ZXJ0X21hcC5wZGYiKQoKI2NyZWF0ZSBhIHZlY3RvciBvZiB0aGUgZXZlbnRJRHMgbm90IGZpbmRpbmcgYSBtYXRjaCBpbiB0aGUgZXZlbnRzIGRhdGFiYXNlCmJhZF9ldmVudElEczwtaW52ZXJ0JGV2ZW50SURbd2hpY2goaXMubmEoaW52ZXJ0JGRlY2ltYWxMYXRpdHVkZSkpXQpgYGAKCiMjIyBNYWtlIEEgU3BvbmdlIE1hcAoKYGBge3Igc3BvbmdlIG1hcHN9CnNwb25nZTwtaW52ZXJ0W3doaWNoKGludmVydCRwaHlsdW09PSJQb3JpZmVyYSIpLF0KI2J5IGluZGl2aWR1YWwKc3BvbmdlMjwtc3BvbmdlICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsIGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUoaW5kaXZpZHVhbENvdW50PXN1bShpbmRpdmlkdWFsQ291bnQsbmEucm0gPSBUKSkgCgojYnkgc3BlY2llcwpzcG9uZ2UzIDwtIHNwb25nZSAlPiUgZ3JvdXBfYnkoc2NpZW50aWZpY05hbWUsIGRlY2ltYWxMYXRpdHVkZSwgZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShjb3VudD1uKCkpCgojcmljaG5lc3MKc3BvbmdlNDwtc3BvbmdlMyAlPiUgZ3JvdXBfYnkoZGVjaW1hbExhdGl0dWRlLGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUocmljaG5lc3M9bigpKQoKc3BvbmdlNTwtbGVmdF9qb2luKHNwb25nZTIsc3BvbmdlNCkKCgoKc3BvbmdlX21hcDwtZ2dtYXAoZG1hcCkgKyBnZW9tX3BvaW50KGRhdGEgPSBzcG9uZ2U1Wy1jKDYxLDYyKSxdLCBtYXBwaW5nID0gYWVzKHggPSBkZWNpbWFsTG9uZ2l0dWRlLCB5ID0gZGVjaW1hbExhdGl0dWRlLCBzaXplPWluZGl2aWR1YWxDb3VudCwgY29sb3I9cmljaG5lc3MpKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJncmVlbiIsIGhpZ2g9InJlZCIpICsgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlPSJUeXBlIFJpY2huZXNzIiwpLCBzaXplPWd1aWRlX2xlZ2VuZCh0aXRsZT0iSW5kaXZpZHVhbCBDb3VudCIpKSArIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpKSAKCnNwb25nZV9tYXAKCmdnc2F2ZShzcG9uZ2VfbWFwLGZpbGVuYW1lPSIuL291dHB1dC9zcG9uZ2VfbWFwLnBkZiIpCgpgYGAKCiMjIE1laW9mYXVuYQoKIyMjIEltcG9ydApgYGB7ciBpbXBvcnQgbWVpb2ZhdW5hfQojbm90ZSBtZWlvIGRhdGEgc3RpbGwgbmVlZCBzb21lIGNsZWFuaW5nLCBpbmNsdWRpbmcgaW1wb3J0aW5nIHNvbWUgc3RhdGlvbnMgZnJvbSBpbnZlcnRzIGFuZCBmaXNoLCBhbmQgZml4aW5nIHVwIGV2ZW50SURzIHRvIGhhdmUgMyBkaWdpdHMgaW5zdGVhZCBvZiAyLiBUaGVyZSBhcmUgMjcgc3BlY2ltZW5zIHRoYXQgZG8gbm90IGhhdmUgc3RhdGlvbiBpbmZvcm1hdGlvbiBiZWNhdXNlIG9mIHRoaXMuCgptZWlvX3NhbXBsZXM8LXJlYWRfZXhjZWwocGF0aD0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9NZWlvZmF1bmEvSGF3YWlpMjAxN19tZWlvZmF1bmFfTWFyaW5lR0VPLnhsc3giLCBzaGVldCA9ICJzcGVjaW1lbiBkYXRhIixza2lwPTEpCgojcmVtb3ZlIGNvbHVtbnMgdGhhdCBkb24ndCBhcHBlYXIgaW4gTWFyaW5lR0VPIHNjaGVtYQptZWlvX3NhbXBsZXM8LW1laW9fc2FtcGxlc1ssLWdyZXAocGF0dGVybiA9ICJeWCIseCA9IG5hbWVzKG1laW9fc2FtcGxlcykscGVybD1UKV0KCiNhZGQgb2NjdXJyZW5jZSBJRHMgdG8gb25lIGludmVzdGlnYXRvcnMgc2FtcGxlcyAtIHRoaXMgaGFzIGJlZW4gdGFrZW4gY2FyZSBvZiBub3cKI21laW9fc2FtcGxlcyRvY2N1cnJlbmNlSURbd2hpY2goaXMubmEobWVpb19zYW1wbGVzJG9jY3VycmVuY2VJRCkpXTwtIlVKIiAKI21ha2Ugb2NjdXJyZW5jZSBJRHMgdW5pcXVlCiNtZWlvX3NhbXBsZXMkb2NjdXJyZW5jZUlEPC1tYWtlLnVuaXF1ZShtZWlvX3NhbXBsZXMkb2NjdXJyZW5jZUlELCBzZXA9Il8iKQoKCmBgYAoKCiMjIyBGb3JtYXQgc2FtcGxlcyB0byBzY2hlbWEKCmBgYHtyIGZvcm1hdCBtZWlvZmF1bmEgc2FtcGxlc30KI2NoYW5nZSBhbGwgZW1wdHkgY29sdW1ucyBmcm9tIGxvZ2ljYWwgdG8gY2hhcmFjdGVyIGNsYXNzCm1laW9fc2FtcGxlc1tzYXBwbHkobWVpb19zYW1wbGVzLCBpcy5sb2dpY2FsKV0gPC0gbGFwcGx5KG1laW9fc2FtcGxlc1tzYXBwbHkobWVpb19zYW1wbGVzLCBpcy5sb2dpY2FsKV0sICBhcy5jaGFyYWN0ZXIpCgptZWlvX3NhbXBsZXMkYmFzaXNvZlJlY29yZDwtInNwZWNpbWVuIiAjY2hlY2sgd2l0aCBGcmV5IHRoYXQgdGhpcyBpcyBjb3JyZWN0Cm1laW9fc2FtcGxlcyRpbnN0aXR1dGlvbklEPC0iVVNOTSIKCiMgY2xhc3MobWVpb19zYW1wbGVzJHNjaWVudGlmaWNOYW1lKSAjZXZlbnR1YWxseSBwYXJzZSB0aGlzIGludG8gdGF4b24gY2F0ZWdvcmllcz8KIyBjbGFzcyhtZWlvX3NhbXBsZXMkdGF4b25SYW5rKSAjdXNpbmcgdGhpcwojIGNsYXNzKG1laW9fc2FtcGxlcyRvY2N1cnJlbmNlSUQpCiMgY2xhc3MobWVpb19zYW1wbGVzJGNhdGFsb2dOdW1iZXIpCiMgY2xhc3MobWVpb19zYW1wbGVzJG90aGVyQ2F0YWxvZ051bWJlcnMpCiMgY2xhc3MobWVpb19zYW1wbGVzJG9yZ2FuaXNtU2NvcGUpCiMgY2xhc3MobWVpb19zYW1wbGVzJGV2ZW50SUQpCiMgY2xhc3MobWVpb19zYW1wbGVzJGlkZW50aWZpZWRCeSkKIyBjbGFzcyhtZWlvX3NhbXBsZXMkaW5kaXZpZHVhbENvdW50KQoKCmBgYAoKIyMjIEpvaW4gdGhlIGV2ZW50IGRhdGEgb250byB0aGUgb2NjdXJyZW5jZSBkYXRhCgpgYGB7ciBtZWlvZmF1bmEgam9pbn0KbWVpbzwtbGVmdF9qb2luKG1laW9fc2FtcGxlcyxtZWlvX2V2ZW50cyxieT0iZXZlbnRJRCIpCmBgYAoKIyMjIE1ha2UgQSBNYXAKYGBge3IgbWVpb2ZhdW5hIG1hcHN9CiNieSBpbmRpdmlkdWFsCm1laW8yPC1tZWlvICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsIGRlY2ltYWxMb25naXR1ZGUpICU+JSBzdW1tYXJpemUoaW5kaXZpZHVhbENvdW50PXN1bShpbmRpdmlkdWFsQ291bnQsbmEucm0gPSBUKSkgCgojYnkgc3BlY2llcwptZWlvMyA8LSBtZWlvICU+JSBncm91cF9ieShzY2llbnRpZmljTmFtZSwgZGVjaW1hbExhdGl0dWRlLCBkZWNpbWFsTG9uZ2l0dWRlKSAlPiUgc3VtbWFyaXplKGNvdW50PW4oKSkKCiNyaWNobmVzcwptZWlvNDwtbWVpbzMgJT4lIGdyb3VwX2J5KGRlY2ltYWxMYXRpdHVkZSxkZWNpbWFsTG9uZ2l0dWRlKSAlPiUgc3VtbWFyaXplKHJpY2huZXNzPW4oKSkKCm1laW81PC1sZWZ0X2pvaW4obWVpbzIsbWVpbzQpCgoKCgptZWlvX21hcDwtZ2dtYXAoZG1hcCkgKyBnZW9tX3BvaW50KGRhdGEgPSBtZWlvNSwgbWFwcGluZyA9IGFlcyh4ID0gZGVjaW1hbExvbmdpdHVkZSwgeSA9IGRlY2ltYWxMYXRpdHVkZSwgc2l6ZT1pbmRpdmlkdWFsQ291bnQsIGNvbG9yPXJpY2huZXNzKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiZ3JlZW4iLCBoaWdoPSJyZWQiKSArIGd1aWRlcyhjb2xvcj1ndWlkZV9jb2xvcmJhcih0aXRsZT0iVHlwZSBSaWNobmVzcyIsKSwgc2l6ZT1ndWlkZV9sZWdlbmQodGl0bGU9IkluZGl2aWR1YWwgQ291bnQiKSkgKyB0aGVtZShheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgCgptZWlvX21hcAoKZ2dzYXZlKG1laW9fbWFwLGZpbGVuYW1lPSIuL291dHB1dC9tZWlvX21hcC5wZGYiKQpgYGAKCiMjIEFSTVMKCiMjIyBJbXBvcnQKYGBge3IgaW1wb3J0IGFybXN9CmFybXNfc2FtcGxlczwtcmVhZF9leGNlbChwYXRoPSIvVXNlcnMvZXJpYy9nb29nbGVfZHJpdmUvTWFyaW5lR0VPL0FSTVMvTWFyaW5lR0VPSElfYmlvYXNzZXNzbWVudF9tYXN0ZXItQVJNUy54bHN4Iiwgc2hlZXQgPSAiU2FtcGxlIikKCmBgYAoKCiMjIyBGb3JtYXQgc2FtcGxlcyB0byBzY2hlbWEKCmBgYHtyIGZvcm1hdCBhcm1zIHNhbXBsZXN9CiNjaGFuZ2UgYWxsIGVtcHR5IGNvbHVtbnMgZnJvbSBsb2dpY2FsIHRvIGNoYXJhY3RlciBjbGFzcwphcm1zX3NhbXBsZXNbc2FwcGx5KGFybXNfc2FtcGxlcywgaXMubG9naWNhbCldIDwtIGxhcHBseShhcm1zX3NhbXBsZXNbc2FwcGx5KGFybXNfc2FtcGxlcywgaXMubG9naWNhbCldLCAgYXMuY2hhcmFjdGVyKQoKIyBjbGFzcyhhcm1zX3NhbXBsZXMkb2NjdXJyZW5jZUlEKQojIGNsYXNzKGFybXNfc2FtcGxlcyRiYXNpc29mUmVjb3JkKQojIGNsYXNzKGFybXNfc2FtcGxlcyRjYXRhbG9nTnVtYmVyKQojIGNsYXNzKGFybXNfc2FtcGxlcyRvdGhlckNhdGFsb2dOdW1iZXJzKQojIGNsYXNzKGFybXNfc2FtcGxlcyRvcmdhbmlzbVNjb3BlKSAjd2VyZSB0aGVyZSBzb21lIHNsdXJyaWVzIHRvbz8KIyBjbGFzcyhhcm1zX3NhbXBsZXMkZXZlbnRJRCkKIyBjbGFzcyhhcm1zX3NhbXBsZXMkc2NpZW50aWZpY05hbWUpICNldmVudHVhbGx5IHBhcnNlIHRoaXMgaW50byB0YXhvbiBjYXRlZ29yaWVzPwojIGNsYXNzKGFybXNfc2FtcGxlcyR0YXhvblJhbmspICN1c2luZyB0aGlzCiMgY2xhc3MoYXJtc19zYW1wbGVzJGlkZW50aWZpZWRCeSkKIyBjbGFzcyhhcm1zX3NhbXBsZXMkaW5kaXZpZHVhbENvdW50KQoKIyBjaGFuZ2UgTkFzIGZvciBpbmRpdmlkdWFsQ291bnQgdG8gMSBmb3Igbm93CmFybXNfc2FtcGxlcyRpbmRpdmlkdWFsQ291bnRbd2hpY2goaXMubmEoYXJtc19zYW1wbGVzJGluZGl2aWR1YWxDb3VudCkpXTwtMQoKYXJtc19zYW1wbGVzJGluc3RpdHV0aW9uSUQ8LSJVU05NIgoKYGBgCgojIyMgSm9pbiB0aGUgZXZlbnQgZGF0YSBvbnRvIHRoZSBvY2N1cnJlbmNlIGRhdGEKCmBgYHtyIGFybXMgam9pbn0KYXJtczwtbGVmdF9qb2luKGFybXNfc2FtcGxlcyxhcm1zX2V2ZW50cyxieT0iZXZlbnRJRCIpCmBgYAoKIyMjIE1ha2UgQSBNYXAKYGBge3IgYXJtcyBtYXBzfQojYnkgaW5kaXZpZHVhbAphcm1zMjwtYXJtcyAlPiUgZ3JvdXBfYnkoZGVjaW1hbExhdGl0dWRlLCBkZWNpbWFsTG9uZ2l0dWRlKSAlPiUgc3VtbWFyaXplKGluZGl2aWR1YWxDb3VudD1zdW0oaW5kaXZpZHVhbENvdW50LG5hLnJtID0gVCkpIAoKI2J5IHNwZWNpZXMKYXJtczMgPC0gYXJtcyAlPiUgZ3JvdXBfYnkoc2NpZW50aWZpY05hbWUsIGRlY2ltYWxMYXRpdHVkZSwgZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShjb3VudD1uKCkpCgojcmljaG5lc3MKYXJtczQ8LWFybXMzICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShyaWNobmVzcz1uKCkpCgphcm1zNTwtbGVmdF9qb2luKGFybXMyLGFybXM0KQoKCgoKYXJtc19tYXA8LWdnbWFwKGRtYXApICsgZ2VvbV9wb2ludChkYXRhID0gYXJtczUsIG1hcHBpbmcgPSBhZXMoeCA9IGRlY2ltYWxMb25naXR1ZGUsIHkgPSBkZWNpbWFsTGF0aXR1ZGUsIHNpemU9aW5kaXZpZHVhbENvdW50LCBjb2xvcj1yaWNobmVzcykpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImdyZWVuIiwgaGlnaD0icmVkIikgKyBndWlkZXMoY29sb3I9Z3VpZGVfY29sb3JiYXIodGl0bGU9IlR5cGUgUmljaG5lc3MiLCksIHNpemU9Z3VpZGVfbGVnZW5kKHRpdGxlPSJJbmRpdmlkdWFsIENvdW50IikpICsgdGhlbWUoYXhpcy50aXRsZT1lbGVtZW50X2JsYW5rKCkpIAoKYXJtc19tYXAKCmdnc2F2ZShhcm1zX21hcCxmaWxlbmFtZT0iLi9vdXRwdXQvYXJtc19tYXAucGRmIikKYGBgCgoKIyMgVmlzdWFsIFRyYW5zZWN0cwoKIyMjIEltcG9ydApgYGB7ciB0cmFuc2VjdHMgaW1wb3J0fQoKdHJhbnNfc2FtcGxlczwtcmVhZF9leGNlbChwYXRoPSIvVXNlcnMvZXJpYy9nb29nbGVfZHJpdmUvTWFyaW5lR0VPL1RyYW5zZWN0cy9iaW9hc3Nlc3NtZW50X0tBTlYueGxzeCIsIHNoZWV0ID0gIlNhbXBsZSIpCgp0cmFuc19vcmdhbmlzbV9waG90b3M8LXJlYWRfZXhjZWwocGF0aD0iL1VzZXJzL2VyaWMvZ29vZ2xlX2RyaXZlL01hcmluZUdFTy9UcmFuc2VjdHMvS0FOVl9waG90by12b3VjaGVyc18yMDE3MDcxMi54bHN4Iiwgc2hlZXQgPSAiU2hlZXQxIikKYGBgCgojIyMgRm9ybWF0LCBjb2xsYXBzZSBhbmQgbWVyZ2UgdGhlIG1lZGlhIGZpZWxkcwoKIyMjIE9yZ2FuaXNtIHBob3RvcwpgYGB7ciB0cmFuc2VjdCBwaG90byBmaWVsZHN9CiMgb3JnYW5pc20gcGhvdG9zCgojIyBkZWxldGUgdGhlIGZpZWxkIHRvIGJlIGFkZGVkIGxhdGVyCnRyYW5zX3NhbXBsZXMkYXNzb2NpYXRlZE1lZGlhPC1OVUxMCgojcG9wIG9mZiB0aGUgZXZlbnRJRCBhZ2FpbiBpbnRvIGl0cyBvd24gZmllbGQKdHJhbnNfb3JnYW5pc21fcGhvdG9zJGV2ZW50SUQ8LXN1YihwYXR0ZXJuPSIoS0FOVlxcZFxcZFxcZClfLisiLHJlcGxhY2VtZW50ID0gIlxcMSIsIHRyYW5zX29yZ2FuaXNtX3Bob3RvcyRhc3NvY2lhdGVkTWVkaWEsIHBlcmw9VCkKCiNwb3Agb2ZmIHRoZSBzcGVjaWVzIG5hbWUgaW50byBpdHMgb3duIGZpZWxkCnRyYW5zX29yZ2FuaXNtX3Bob3RvcyRzY2llbnRpZmljTmFtZTwtc3ViKHBhdHRlcm49Ii4rXyhcXGR7OH0pXyhcXHcrLVthLXpdKylfLisiLCByZXBsYWNlbWVudCA9ICJcXDIiLCB0cmFuc19vcmdhbmlzbV9waG90b3MkYXNzb2NpYXRlZE1lZGlhLHBlcmw9VCkKdHJhbnNfb3JnYW5pc21fcGhvdG9zJHNjaWVudGlmaWNOYW1lPC1zdWIocGF0dGVybj0iLSIsIHJlcGxhY2VtZW50PSIgIix4ID0gdHJhbnNfb3JnYW5pc21fcGhvdG9zJHNjaWVudGlmaWNOYW1lKQoKI3BvcCBvZmYgdGhlIGluaXRpYWxzIG9mIHRoZSBjb2xsZWN0b3IsIGFuZCByZXBsYWNlIHdpdGggZnVsbCBuYW1lCnRyYW5zX29yZ2FuaXNtX3Bob3RvcyRpZGVudGlmaWVkQnk8LXN0cl9leHRyYWN0KHBhdHRlcm49IlpGfFJXIiwgc3RyaW5nPXRyYW5zX29yZ2FuaXNtX3Bob3RvcyRhc3NvY2lhdGVkTWVkaWEpCnRyYW5zX29yZ2FuaXNtX3Bob3RvcyRpZGVudGlmaWVkQnlbd2hpY2godHJhbnNfb3JnYW5pc21fcGhvdG9zJGlkZW50aWZpZWRCeT09IlpGIildPC0iWmFjaCBGb2x0eiIKdHJhbnNfb3JnYW5pc21fcGhvdG9zJGlkZW50aWZpZWRCeVt3aGljaCh0cmFuc19vcmdhbmlzbV9waG90b3MkaWRlbnRpZmllZEJ5PT0iUlciKV08LSJSb3NzIFdoaXBwbyIKCiN1c2UgZGRwbHkgdG8gbHVtcCBhbGwgYXNzb2NpYXRlZE1lZGlhIGludG8gYSBzaW5nbGUgZmllbGQsIHNlcGFyYXRlZCBieSBhIHwKdHJhbnNfYXNzb2NpYXRlZE1lZGlhPC1kZHBseSh0cmFuc19vcmdhbmlzbV9waG90b3MsIGMoImV2ZW50SUQiLCJzY2llbnRpZmljTmFtZSIsImlkZW50aWZpZWRCeSIpLCB0cmFuc2Zvcm0sIGFzc29jaWF0ZWRNZWRpYSA9IHBhc3RlKGFzc29jaWF0ZWRNZWRpYSwgY29sbGFwc2UgPSAifCIpKQoKI3JlbW92ZSBhbGwgYnV0IHRoZSBmaXJzdCBpbnN0YW5jZQp0cmFuc19hc3NvY2lhdGVkTWVkaWE8LXRyYW5zX2Fzc29jaWF0ZWRNZWRpYVshZHVwbGljYXRlZCh0cmFuc19hc3NvY2lhdGVkTWVkaWEkYXNzb2NpYXRlZE1lZGlhKSxdCgp0cmFuc19zYW1wbGVzPC1sZWZ0X2pvaW4odHJhbnNfc2FtcGxlcywgdHJhbnNfYXNzb2NpYXRlZE1lZGlhLCBieT1jKCJldmVudElEIiwic2NpZW50aWZpY05hbWUiLCJpZGVudGlmaWVkQnkiKSkKCmBgYAoKIyMjIEZvcm1hdCBzYW1wbGVzIHRvIHNjaGVtYQoKYGBge3IgZm9ybWF0IHRyYW5zZWN0IHNhbXBsZXN9CiNjaGFuZ2UgYWxsIGVtcHR5IGNvbHVtbnMgZnJvbSBsb2dpY2FsIHRvIGNoYXJhY3RlciBjbGFzcwp0cmFuc19zYW1wbGVzW3NhcHBseSh0cmFuc19zYW1wbGVzLCBpcy5sb2dpY2FsKV0gPC0gbGFwcGx5KHRyYW5zX3NhbXBsZXNbc2FwcGx5KHRyYW5zX3NhbXBsZXMsIGlzLmxvZ2ljYWwpXSwgIGFzLmNoYXJhY3RlcikKCiMgY2xhc3ModHJhbnNfc2FtcGxlcyRvY2N1cnJlbmNlSUQpCiMgY2xhc3ModHJhbnNfc2FtcGxlcyRiYXNpc29mUmVjb3JkKQojIGNsYXNzKHRyYW5zX3NhbXBsZXMkY2F0YWxvZ051bWJlcikKIyBjbGFzcyh0cmFuc19zYW1wbGVzJG90aGVyQ2F0YWxvZ051bWJlcnMpCiMgY2xhc3ModHJhbnNfc2FtcGxlcyRvcmdhbmlzbVNjb3BlKQojIGNsYXNzKHRyYW5zX3NhbXBsZXMkZXZlbnRJRCkKIyBjbGFzcyh0cmFuc19zYW1wbGVzJHNjaWVudGlmaWNOYW1lKSAjZXZlbnR1YWxseSBwYXJzZSB0aGlzIGludG8gdGF4b24gY2F0ZWdvcmllcz8KIyBjbGFzcyh0cmFuc19zYW1wbGVzJHRheG9uUmFuaykgI3VzaW5nIHRoaXMKIyBjbGFzcyh0cmFuc19zYW1wbGVzJGlkZW50aWZpZWRCeSkKIyBjbGFzcyh0cmFuc19zYW1wbGVzJGluZGl2aWR1YWxDb3VudCkKCnRyYW5zX3NhbXBsZXMkaW5zdGl0dXRpb25JRDwtIlVTTk0iCgoKCgpgYGAKCiMjIyBKb2luIHRoZSBldmVudCBkYXRhIG9udG8gdGhlIG9jY3VycmVuY2UgZGF0YQoKYGBge3Igam9pbiB0cmFuc2VjdHN9CnRyYW5zPC1sZWZ0X2pvaW4odHJhbnNfc2FtcGxlcyx0cmFuc19ldmVudHMsYnk9ImV2ZW50SUQiKQpgYGAKCiMjIyBNYWtlIEEgTWFwCmBgYHtyIHRyYW5zZWN0IG1hcHN9CiNieSBpbmRpdmlkdWFsCnRyYW5zMjwtdHJhbnMgJT4lIGdyb3VwX2J5KGRlY2ltYWxMYXRpdHVkZSwgZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShpbmRpdmlkdWFsQ291bnQ9c3VtKGluZGl2aWR1YWxDb3VudCxuYS5ybSA9IFQpKSAKCiNieSBzcGVjaWVzCnRyYW5zMyA8LSB0cmFucyAlPiUgZ3JvdXBfYnkoc2NpZW50aWZpY05hbWUsIGRlY2ltYWxMYXRpdHVkZSwgZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShjb3VudD1uKCksIGluZGl2aWR1YWxDb3VudD1zdW0oaW5kaXZpZHVhbENvdW50LG5hLnJtPVQpKQoKI3JpY2huZXNzCnRyYW5zNDwtdHJhbnMzICU+JSBncm91cF9ieShkZWNpbWFsTGF0aXR1ZGUsZGVjaW1hbExvbmdpdHVkZSkgJT4lIHN1bW1hcml6ZShyaWNobmVzcz1uKCkpCgp0cmFuczU8LWxlZnRfam9pbih0cmFuczIsdHJhbnM0KQoKCgoKdHJhbnNfbWFwPC1nZ21hcChkbWFwKSArIGdlb21fcG9pbnQoZGF0YSA9IHRyYW5zNSwgbWFwcGluZyA9IGFlcyh4ID0gZGVjaW1hbExvbmdpdHVkZSwgeSA9IGRlY2ltYWxMYXRpdHVkZSwgc2l6ZT1pbmRpdmlkdWFsQ291bnQsIGNvbG9yPXJpY2huZXNzKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiZ3JlZW4iLCBoaWdoPSJyZWQiKSArIGd1aWRlcyhjb2xvcj1ndWlkZV9jb2xvcmJhcih0aXRsZT0iU3BlY2llcyBSaWNobmVzcyIsKSwgc2l6ZT1ndWlkZV9sZWdlbmQodGl0bGU9IkluZGl2aWR1YWwgQ291bnQiKSkgKyB0aGVtZShheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgCgp0cmFuc19tYXAKCmdnc2F2ZSh0cmFuc19tYXAsZmlsZW5hbWU9Ii4vb3V0cHV0L3RyYW5zX21hcC5wZGYiKQpgYGAKCiMgRmluYWwgRGF0YWJhc2UKCk5vdyB0byBqb2luIGV2ZXJ5dGhpbmcgaW50byBvbmUgbW9uc3RlciBkYXRhYmFzZQoKYGBge3J9CmE8LWZ1bGxfam9pbihmaXNoLGFsZ2FlKQpiPC1mdWxsX2pvaW4oYSxpbnZlcnQpCmM8LWZ1bGxfam9pbihiLG1laW8pCmQ8LWZ1bGxfam9pbihjLGFybXMpCk1hcmluZUdFT0hJPC1mdWxsX2pvaW4oZCx0cmFucykKCiNyZWFkIGluIHRoZSBmbGF0IHNjaGVtYQpmbGF0X3NjaGVtYTwtYXMudmVjdG9yKHJlYWQuY3N2KCJmbGF0X3NjaGVtYS5jc3YiLCBoZWFkZXI9Riwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpKQoKI3JlZHVjZSB0aGUgam9pbmVkIGRhdGFiYXNlIHRvIGp1c3QgdGhlIGNvbHVtbnMgaW4gdGhlIHNjaGVtYSwgYW5kIHNvcnQgb24gY29sdW1uIG9yZGVyCk1hcmluZUdFT0hJMjwtTWFyaW5lR0VPSElbLG1hdGNoKGZsYXRfc2NoZW1hLCBuYW1lcyhNYXJpbmVHRU9ISSkpXQoKd3JpdGUuY3N2KE1hcmluZUdFT0hJMiwiLi9vdXRwdXQvTWFyaW5lR0VPSElfZGF0YV8xLjEuY3N2Iixyb3cubmFtZXMgPSBGKQoKI1dyaXRlWExTKGMoTWFyaW5lR0VPSEkyLGFzLmRhdGEuZnJhbWUoZXZlbnRzKSksRXhjZWxGaWxlTmFtZSA9ICIuL291dHB1dC9NYXJpbmVHRU9ISV9kYXRhXzEuMS54bHN4IixTaGVldE5hbWVzPWMoIkV2ZW50cyIsIlNhbXBsZXMiKSkKCmBgYA==